diff options
Diffstat (limited to 'host/lib')
74 files changed, 3912 insertions, 1394 deletions
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index d8c6fad70..3fa8ed22f 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -103,8 +103,24 @@ IF(MSVC)      IF(UHD_VERSION_DEVEL)          SET(RC_TRIMMED_VERSION_PATCH "999")      ENDIF(UHD_VERSION_DEVEL) + +    # Allow a custom .rc template file to be used +    IF(CUSTOM_RC_FILE) +        IF(IS_ABSOLUTE "${CUSTOM_RC_FILE}") +            SET(UHD_RC_IN "${CUSTOM_RC_FILE}") +        ELSE() +            SET(UHD_RC_IN "${CMAKE_BINARY_DIR}/${CUSTOM_RC_FILE}") +        ENDIF(IS_ABSOLUTE "${CUSTOM_RC_FILE}") +        MESSAGE(STATUS "") +        MESSAGE(STATUS "Using custom RC template: ${UHD_RC_IN}") +        MESSAGE(STATUS "") +    ELSE() +        SET(UHD_RC_IN "${CMAKE_CURRENT_SOURCE_DIR}/uhd.rc.in") +    ENDIF(CUSTOM_RC_FILE) +    SET(UHD_RC_IN ${UHD_RC_IN} CACHE STRING "uhd.rc template filepath") +      CONFIGURE_FILE( -        ${CMAKE_CURRENT_SOURCE_DIR}/uhd.rc.in +        ${UHD_RC_IN}          ${CMAKE_CURRENT_BINARY_DIR}/uhd.rc      @ONLY) diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt index 5204c29ea..024c2260b 100644 --- a/host/lib/convert/CMakeLists.txt +++ b/host/lib/convert/CMakeLists.txt @@ -22,40 +22,6 @@ INCLUDE(CheckIncludeFileCXX)  MESSAGE(STATUS "")  ######################################################################## -# Look for Orc support -######################################################################## -FIND_PACKAGE(ORC) - -IF(NOT ORCC_EXECUTABLE) -    FIND_PROGRAM(ORCC_EXECUTABLE orcc) -ENDIF() - -LIBUHD_REGISTER_COMPONENT("ORC" ENABLE_ORC ON "ENABLE_LIBUHD;ORC_FOUND;ORCC_EXECUTABLE" OFF) - -IF(ENABLE_ORC) -    INCLUDE_DIRECTORIES(${ORC_INCLUDE_DIRS}) -    LINK_DIRECTORIES(${ORC_LIBRARY_DIRS}) -    ENABLE_LANGUAGE(C) - -    SET(orcc_src ${CMAKE_CURRENT_SOURCE_DIR}/convert_orc.orc) - -    GET_FILENAME_COMPONENT(orc_file_name_we ${orcc_src} NAME_WE) -    SET(orcc_gen ${CMAKE_CURRENT_BINARY_DIR}/${orc_file_name_we}.c) -    MESSAGE(STATUS "Orc found, enabling Orc support.") -    ADD_CUSTOM_COMMAND( -        COMMAND ${ORCC_EXECUTABLE} --implementation -o ${orcc_gen} ${orcc_src} -        DEPENDS ${orcc_src} OUTPUT ${orcc_gen} -    ) -    LIBUHD_APPEND_SOURCES(${orcc_gen}) -    LIBUHD_APPEND_SOURCES( -        ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_orc.cpp -    ) -    LIBUHD_APPEND_LIBS(${ORC_LIBRARIES}) -ELSE(ENABLE_ORC) -    MESSAGE(STATUS "Orc not found, disabling orc support.") -ENDIF(ENABLE_ORC) - -########################################################################  # Check for SSE2 SIMD headers  ########################################################################  IF(CMAKE_COMPILER_IS_GNUCXX) diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp index 6c2ea9fec..65fdcbea2 100644 --- a/host/lib/convert/convert_common.hpp +++ b/host/lib/convert/convert_common.hpp @@ -65,11 +65,10 @@ static const int PRIORITY_GENERAL = 0;  static const int PRIORITY_EMPTY = -1;  #ifdef __ARM_NEON__ -static const int PRIORITY_LIBORC = 3; -static const int PRIORITY_SIMD = 2; //neon conversions could be implemented better, orc wins +static const int PRIORITY_SIMD = 2;  static const int PRIORITY_TABLE = 1; //tables require large cache, so they are slower on arm  #else -static const int PRIORITY_LIBORC = 2; +// We used to have ORC, too, so SIMD is 3  static const int PRIORITY_SIMD = 3;  static const int PRIORITY_TABLE = 1;  #endif diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp index 329e94a4d..fd6c8497e 100644 --- a/host/lib/convert/convert_impl.cpp +++ b/host/lib/convert/convert_impl.cpp @@ -43,10 +43,10 @@ bool convert::operator==(const convert::id_type &lhs, const convert::id_type &rh  std::string convert::id_type::to_pp_string(void) const{      return str(boost::format(          "conversion ID\n" -        "  Input format: %s\n" -        "  Num inputs: %d\n" +        "  Input format:  %s\n" +        "  Num inputs:    %d\n"          "  Output format: %s\n" -        "  Num outputs: %d\n" +        "  Num outputs:   %d\n"      )          % this->input_format          % this->num_inputs @@ -55,6 +55,15 @@ std::string convert::id_type::to_pp_string(void) const{      );  } +std::string convert::id_type::to_string(void) const{ +    return str(boost::format("%s (%d) -> %s (%d)") +        % this->input_format +        % this->num_inputs +        % this->output_format +        % this->num_outputs +    ); +} +  /***********************************************************************   * Setup the table registry   **********************************************************************/ @@ -92,7 +101,15 @@ convert::function_type convert::get_converter(      //find a matching priority      priority_type best_prio = -1;      BOOST_FOREACH(priority_type prio_i, get_table()[id].keys()){ -        if (prio_i == prio) return get_table()[id][prio]; +        if (prio_i == prio) { +            //----------------------------------------------------------------// +            UHD_LOGV(always) << "get_converter: For converter ID: " << id.to_pp_string() << std::endl +                << "Using prio: " << prio << std::endl +                << std::endl +            ; +            //----------------------------------------------------------------// +            return get_table()[id][prio]; +        }          best_prio = std::max(best_prio, prio_i);      } @@ -100,6 +117,13 @@ convert::function_type convert::get_converter(      if (prio != -1) throw uhd::key_error(          "Cannot find a conversion routine [with prio] for " + id.to_pp_string()); +    //----------------------------------------------------------------// +    UHD_LOGV(always) << "get_converter: For converter ID: " << id.to_pp_string() << std::endl +        << "Using prio: " << best_prio << std::endl +        << std::endl +    ; +    //----------------------------------------------------------------// +      //otherwise, return best prio      return get_table()[id][best_prio];  } diff --git a/host/lib/convert/convert_orc.orc b/host/lib/convert/convert_orc.orc deleted file mode 100644 index ffb298f26..000000000 --- a/host/lib/convert/convert_orc.orc +++ /dev/null @@ -1,79 +0,0 @@ -.function _convert_fc32_1_to_item32_1_nswap_orc -.source 8 src -.dest 4 dst -.floatparam 4 scalar -.temp 8 scaled -.temp 8 converted -.temp 4 short -x2 mulf scaled, src, scalar -x2 convfl converted, scaled -x2 convlw short, converted -swapl short, short -x2 swapw dst, short - -.function _convert_fc32_1_to_item32_1_bswap_orc -.source 8 src -.dest 4 dst -.floatparam 4 scalar -.temp 8 scaled -.temp 8 converted -.temp 4 short -x2 mulf scaled, src, scalar -x2 convfl converted, scaled -x2 convlw short, converted -x2 swapw dst, short - -.function _convert_item32_1_to_fc32_1_nswap_orc -.source 4 src -.dest 8 dst -.floatparam 4 scalar -.temp 4 tmp1 -.temp 8 tmp2 -x2 swapw tmp1, src -swapl tmp1, tmp1 -x2 convswl tmp2, tmp1 -x2 convlf tmp2, tmp2 -x2 mulf dst, tmp2, scalar - -.function _convert_item32_1_to_fc32_1_bswap_orc -.source 4 src -.dest 8 dst -.floatparam 4 scalar -.temp 4 tmp1 -.temp 8 tmp2 -x2 swapw tmp1, src -x2 convswl tmp2, tmp1 -x2 convlf tmp2, tmp2 -x2 mulf dst, tmp2, scalar - -.function _convert_sc16_1_to_item32_1_nswap_orc -.source 4 src -.dest 4 dst -.temp 4 tmp -.floatparam 4 scalar -swapl tmp, src -x2 swapw dst, tmp - -.function _convert_item32_1_to_sc16_1_nswap_orc -.source 4 src -.dest 4 dst -.floatparam 4 scalar -.temp 4 tmp -x2 swapw tmp, src -swapl dst, tmp - -.function _convert_swap_byte_pairs_orc -.source 4 src -.dest 4 dst -swapl dst, src - -.function _convert_fc32_1_to_sc8_1_nswap_orc -.source 8 src -.dest 2 dst -.temp 8 tmp -.temp 4 tmp2 -.floatparam 4 scalar -x2 mulf tmp, src, scalar -x2 convfl tmp, tmp -x2 convlw tmp2, tmp -x2 convwb dst, tmp2 diff --git a/host/lib/convert/convert_with_orc.cpp b/host/lib/convert/convert_with_orc.cpp deleted file mode 100644 index 19755fa44..000000000 --- a/host/lib/convert/convert_with_orc.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright 2011-2013 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> - -using namespace uhd::convert; - -extern "C" { -extern void _convert_fc32_1_to_item32_1_nswap_orc(void *, const void *, float, int); -extern void _convert_fc32_1_to_item32_1_bswap_orc(void *, const void *, float, int); -extern void _convert_item32_1_to_fc32_1_nswap_orc(void *, const void *, float, int); -extern void _convert_item32_1_to_fc32_1_bswap_orc(void *, const void *, float, int); -extern void _convert_sc16_1_to_item32_1_nswap_orc(void *, const void *, float, int); -extern void _convert_item32_1_to_sc16_1_nswap_orc(void *, const void *, float, int); -extern void _convert_fc32_1_to_sc8_1_nswap_orc(void *, const void *, float, int); -extern void _convert_swap_byte_pairs_orc(void *, const void *, int); -} - -DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_LIBORC){ -    _convert_fc32_1_to_item32_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_LIBORC){ -    _convert_fc32_1_to_item32_1_bswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_LIBORC){ -    _convert_item32_1_to_fc32_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_LIBORC){ -    _convert_item32_1_to_fc32_1_bswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(sc16, 1, sc16_item32_le, 1, PRIORITY_LIBORC){ -    _convert_sc16_1_to_item32_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(sc16_item32_le, 1, sc16, 1, PRIORITY_LIBORC){ -    _convert_item32_1_to_sc16_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_LIBORC){ -    _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -} - -DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_LIBORC){ -    _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps); -    _convert_swap_byte_pairs_orc(outputs[0], outputs[0], (nsamps + 1)/2); -} diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py index b0790755a..8090f14bd 100644 --- a/host/lib/convert/gen_convert_general.py +++ b/host/lib/convert/gen_convert_general.py @@ -17,92 +17,94 @@  #  TMPL_HEADER = """ -#import time +<% +    import time +%>  /*********************************************************************** - * This file was generated by $file on $time.strftime("%c") + * This file was generated by ${file} on ${time.strftime("%c")}   **********************************************************************/ -\#include "convert_common.hpp" -\#include <uhd/utils/byteswap.hpp> +#include "convert_common.hpp" +#include <uhd/utils/byteswap.hpp>  using namespace uhd::convert;  """  TMPL_CONV_GEN2_ITEM32 = """ -DECLARE_CONVERTER(item32, 1, sc16_item32_$(end), 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(item32, 1, sc16_item32_${end}, 1, PRIORITY_GENERAL){      const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);      item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);      for (size_t i = 0; i < nsamps; i++){ -        output[i] = $(to_wire)(input[i]); +        output[i] = ${to_wire}(input[i]);      }  } -DECLARE_CONVERTER(sc16_item32_$(end), 1, item32, 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(sc16_item32_${end}, 1, item32, 1, PRIORITY_GENERAL){      const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);      item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);      for (size_t i = 0; i < nsamps; i++){ -        output[i] = $(to_host)(input[i]); +        output[i] = ${to_host}(input[i]);      }  }  """  TMPL_CONV_USRP1_COMPLEX = """ -DECLARE_CONVERTER($(cpu_type), $(width), sc16_item16_usrp1, 1, PRIORITY_GENERAL){ -    #for $w in range($width) -    const $(cpu_type)_t *input$(w) = reinterpret_cast<const $(cpu_type)_t *>(inputs[$(w)]); -    #end for +DECLARE_CONVERTER(${cpu_type}, ${width}, sc16_item16_usrp1, 1, PRIORITY_GENERAL){ +    % for w in range(width): +    const ${cpu_type}_t *input${w} = reinterpret_cast<const ${cpu_type}_t *>(inputs[${w}]); +    % endfor      boost::uint16_t *output = reinterpret_cast<boost::uint16_t *>(outputs[0]);      for (size_t i = 0, j = 0; i < nsamps; i++){ -        #for $w in range($width) -        output[j++] = $(to_wire)(boost::uint16_t(boost::int16_t(input$(w)[i].real()$(do_scale)))); -        output[j++] = $(to_wire)(boost::uint16_t(boost::int16_t(input$(w)[i].imag()$(do_scale)))); -        #end for +        % for w in range(width): +        output[j++] = ${to_wire}(boost::uint16_t(boost::int16_t(input${w}[i].real()${do_scale}))); +        output[j++] = ${to_wire}(boost::uint16_t(boost::int16_t(input${w}[i].imag()${do_scale}))); +        % endfor      }  } -DECLARE_CONVERTER(sc16_item16_usrp1, 1, $(cpu_type), $(width), PRIORITY_GENERAL){ +DECLARE_CONVERTER(sc16_item16_usrp1, 1, ${cpu_type}, ${width}, PRIORITY_GENERAL){      const boost::uint16_t *input = reinterpret_cast<const boost::uint16_t *>(inputs[0]); -    #for $w in range($width) -    $(cpu_type)_t *output$(w) = reinterpret_cast<$(cpu_type)_t *>(outputs[$(w)]); -    #end for +    % for w in range(width): +    ${cpu_type}_t *output${w} = reinterpret_cast<${cpu_type}_t *>(outputs[${w}]); +    % endfor      for (size_t i = 0, j = 0; i < nsamps; i++){ -        #for $w in range($width) -        output$(w)[i] = $(cpu_type)_t( -            boost::int16_t($(to_host)(input[j+0]))$(do_scale), -            boost::int16_t($(to_host)(input[j+1]))$(do_scale) +        % for w in range(width): +        output${w}[i] = ${cpu_type}_t( +            boost::int16_t(${to_host}(input[j+0]))${do_scale}, +            boost::int16_t(${to_host}(input[j+1]))${do_scale}          );          j += 2; -        #end for +        % endfor      }  } -DECLARE_CONVERTER(sc8_item16_usrp1, 1, $(cpu_type), $(width), PRIORITY_GENERAL){ +DECLARE_CONVERTER(sc8_item16_usrp1, 1, ${cpu_type}, ${width}, PRIORITY_GENERAL){      const boost::uint16_t *input = reinterpret_cast<const boost::uint16_t *>(inputs[0]); -    #for $w in range($width) -    $(cpu_type)_t *output$(w) = reinterpret_cast<$(cpu_type)_t *>(outputs[$(w)]); -    #end for +    % for w in range(width): +    ${cpu_type}_t *output${w} = reinterpret_cast<${cpu_type}_t *>(outputs[${w}]); +    % endfor      for (size_t i = 0, j = 0; i < nsamps; i++){ -        #for $w in range($width) +        % for w in range(width):          { -        const boost::uint16_t num = $(to_host)(input[j++]); -        output$(w)[i] = $(cpu_type)_t( -            boost::int8_t(num)$(do_scale), -            boost::int8_t(num >> 8)$(do_scale) +        const boost::uint16_t num = ${to_host}(input[j++]); +        output${w}[i] = ${cpu_type}_t( +            boost::int8_t(num)${do_scale}, +            boost::int8_t(num >> 8)${do_scale}          );          } -        #end for +        % endfor      }  }  """  def parse_tmpl(_tmpl_text, **kwargs): -    from Cheetah.Template import Template -    return str(Template(_tmpl_text, kwargs)) +    from mako.template import Template +    return Template(_tmpl_text).render(**kwargs)  if __name__ == '__main__':      import sys, os diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index 24f5bf8be..5c0cfc109 100644..100755 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -1,5 +1,5 @@  # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2010-2011,2015 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,105 +18,99 @@  import re  import sys  import math -from Cheetah.Template import Template +from mako.template import Template -COMMON_TMPL = """\ -#import time +COMMON_TMPL = """<% import time %>\  /*********************************************************************** - * This file was generated by $file on $time.strftime("%c") + * This file was generated by ${file} on ${time.strftime("%c")}   **********************************************************************/ -\#ifndef INCLUDED_$(name.upper())_HPP -\#define INCLUDED_$(name.upper())_HPP +#ifndef INCLUDED_${name.upper()}_HPP +#define INCLUDED_${name.upper()}_HPP -\#include <uhd/config.hpp> -\#include <uhd/exception.hpp> -\#include <boost/cstdint.hpp> -\#include <set> +#include <uhd/config.hpp> +#include <uhd/exception.hpp> +#include <boost/cstdint.hpp> +#include <set> -class $(name)_t{ +class ${name}_t{  public: -    #for $reg in $regs -    #if $reg.get_enums() -    enum $reg.get_type(){ -        #for $i, $enum in enumerate($reg.get_enums()) -        #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' -        $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma -        #end for +    % for reg in regs: +    % if reg.get_enums(): +    enum ${reg.get_type()}{ +        % for i,enum in enumerate(reg.get_enums()): +        ${reg.get_name().upper()}_${enum[0].upper()} = ${enum[1]}<% comma = ',' if i != (len(reg.get_enums())-1) else '' %>${comma} +        % endfor      }; -    #end if -    $reg.get_type() $reg.get_name(); -    #end for +    % endif +    ${reg.get_type()} ${reg.get_name()}; +    % endfor -    $(name)_t(void){ +    ${name}_t(void){          _state = NULL; -        #for $reg in $regs -        $reg.get_name() = $reg.get_default(); -        #end for +        % for reg in regs: +        ${reg.get_name()} = ${reg.get_default()}; +        % endfor      } -    ~$(name)_t(void){ +    ~${name}_t(void){          delete _state;      } -    $body +    ${body}      void save_state(void){ -        if (_state == NULL) _state = new $(name)_t(); -        #for $reg in $regs -        _state->$reg.get_name() = this->$reg.get_name(); -        #end for +        if (_state == NULL) _state = new ${name}_t(); +        % for reg in regs: +        _state->${reg.get_name()} = this->${reg.get_name()}; +        % endfor      }      template<typename T> std::set<T> get_changed_addrs(void){          if (_state == NULL) throw uhd::runtime_error("no saved state");          //check each register for changes          std::set<T> addrs; -        #for $reg in $regs -        if(_state->$reg.get_name() != this->$reg.get_name()){ -            addrs.insert($reg.get_addr()); +        % for reg in regs: +        if(_state->${reg.get_name()} != this->${reg.get_name()}){ +            addrs.insert(${reg.get_addr()});          } -        #end for +        % endfor          return addrs;      } -    #for $mreg in $mregs -    $mreg.get_type() get_$(mreg.get_name())(void){ -        return -        #set $shift = 0 -        #for $reg in $mreg.get_regs() -        ($(mreg.get_type())($reg.get_name() & $reg.get_mask()) << $shift) | -            #set $shift = $shift + $reg.get_bit_width() -        #end for +    % for mreg in mregs: +    ${mreg.get_type()} get_${mreg.get_name()}(void){ +        return <% shift = 0 %> +        % for reg in mreg.get_regs(): +        (${mreg.get_type()}(${reg.get_name()} & ${reg.get_mask()}) << ${shift}) |<% shift = shift + reg.get_bit_width() %> +        % endfor          0;      } -    void set_$(mreg.get_name())($mreg.get_type() reg){ -        #set $shift = 0 -        #for $reg in $mreg.get_regs() -        $reg.get_name() = (reg >> $shift) & $reg.get_mask(); -            #set $shift = $shift + $reg.get_bit_width() -        #end for +    void set_${mreg.get_name()}(${mreg.get_type()} reg){<% shift = 0 %> +        % for reg in mreg.get_regs(): +        ${reg.get_name()} = (reg >> ${shift}) & ${reg.get_mask()};<% shift = shift + reg.get_bit_width() %> +        % endfor      } -    #end for +    % endfor  private: -    $(name)_t *_state; +    ${name}_t *_state;  }; -\#endif /* INCLUDED_$(name.upper())_HPP */ +#endif /* INCLUDED_${name.upper()}_HPP */  """  def parse_tmpl(_tmpl_text, **kwargs): -    return str(Template(_tmpl_text, kwargs)) +    return Template(_tmpl_text).render(**kwargs)  def to_num(arg): return int(eval(arg))  class reg:      def __init__(self, reg_des):          try: self.parse(reg_des) -        except Exception, e: -            raise Exception, 'Error parsing register description: "%s"\nWhat: %s'%(reg_des, e) +        except Exception as e: +            raise Exception('Error parsing register description: "%s"\nWhat: %s'%(reg_des, e))      def parse(self, reg_des):          x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) @@ -133,7 +127,8 @@ class reg:          self._enums = list()          if enums:              enum_val = 0 -            for enum_str in map(str.strip, enums.split(',')): +            for enum_str_unstripped in enums.split(','): +                enum_str = enum_str_unstripped.strip()                  if '=' in enum_str:                      enum_name, enum_val = enum_str.split('=')                      enum_val = to_num(enum_val) @@ -146,7 +141,7 @@ class reg:      def get_name(self): return self._name      def get_default(self):          for key, val in self.get_enums(): -            if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) +            if val == self._default: return ('%s_%s'%(self.get_name(), key)).upper()          return self._default      def get_type(self):          if self.get_enums(): return '%s_t'%self.get_name() @@ -158,14 +153,14 @@ class reg:  class mreg:      def __init__(self, mreg_des, regs):          try: self.parse(mreg_des, regs) -        except Exception, e: -            raise Exception, 'Error parsing meta register description: "%s"\nWhat: %s'%(mreg_des, e) +        except Exception as e: +            raise Exception('Error parsing meta register description: "%s"\nWhat: %s'%(mreg_des, e))      def parse(self, mreg_des, regs):          x = re.match('^~(\w*)\s+(.*)\s*$', mreg_des)          self._name, reg_names = x.groups()          regs_dict = dict([(reg.get_name(), reg) for reg in regs]) -        self._regs = [regs_dict[reg_name] for reg_name in map(str.strip, reg_names.split(','))] +        self._regs = [regs_dict[reg_name.strip()] for reg_name in reg_names.split(',')]      def get_name(self): return self._name      def get_regs(self): return self._regs diff --git a/host/lib/ic_reg_maps/gen_ad5623_regs.py b/host/lib/ic_reg_maps/gen_ad5623_regs.py index e653921ba..8b70a9f0a 100755 --- a/host/lib/ic_reg_maps/gen_ad5623_regs.py +++ b/host/lib/ic_reg_maps/gen_ad5623_regs.py @@ -32,9 +32,9 @@ cmd              0[19:21]          0       wr_input_n, up_dac_n, wr_input_n_up_a  BODY_TMPL="""\  boost::uint32_t get_reg(void){      boost::uint32_t reg = 0; -    #for $reg in filter(lambda r: r.get_addr() == 0, $regs) -    reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -    #end for +    % for reg in filter(lambda r: r.get_addr() == 0, regs): +    reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +    % endfor      return reg;  }  """ diff --git a/host/lib/ic_reg_maps/gen_ad7922_regs.py b/host/lib/ic_reg_maps/gen_ad7922_regs.py index 5cec1924a..c77991182 100755 --- a/host/lib/ic_reg_maps/gen_ad7922_regs.py +++ b/host/lib/ic_reg_maps/gen_ad7922_regs.py @@ -32,16 +32,16 @@ chn              0[13]          0  BODY_TMPL="""\  boost::uint16_t get_reg(void){      boost::uint16_t reg = 0; -    #for $reg in filter(lambda r: r.get_addr() == 0, $regs) -    reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -    #end for +    % for reg in filter(lambda r: r.get_addr() == 0, regs): +    reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +    % endfor      return reg;  }  void set_reg(boost::uint16_t reg){ -    #for $reg in filter(lambda r: r.get_addr() == 0, $regs) -    $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -    #end for +    % for reg in filter(lambda r: r.get_addr() == 0, regs): +    ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +    % endfor  }  """ diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py index 6c1e612cc..9f194b5c9 100755 --- a/host/lib/ic_reg_maps/gen_ad9510_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py @@ -54,25 +54,25 @@ lock_detect_disable            0xD[6]        0      enb, dis  ########################################################################  ## fine delay adjust  ######################################################################## -#for $i, $o in ((5, 0), (6, 4)) -delay_control_out$i            $hex(0x34+$o)[0]    0 -ramp_current_out$i             $hex(0x35+$o)[0:2]  0   200ua, 400ua, 600ua, 800ua, 1000ua, 1200ua, 1400ua, 1600ua -ramp_capacitor_out$i           $hex(0x35+$o)[3:5]  0   4caps=0, 3caps=1, 2caps=3, 1cap=7 -delay_fine_adjust_out$i        $hex(0x36+$o)[1:5]  0 -#end for +% for i, o in ((5, 0), (6, 4)): +delay_control_out${i}            ${hex(0x34+o)}[0]    0 +ramp_current_out${i}             ${hex(0x35+o)}[0:2]  0   200ua, 400ua, 600ua, 800ua, 1000ua, 1200ua, 1400ua, 1600ua +ramp_capacitor_out${i}           ${hex(0x35+o)}[3:5]  0   4caps=0, 3caps=1, 2caps=3, 1cap=7 +delay_fine_adjust_out${i}        ${hex(0x36+o)}[1:5]  0 +% endfor  ########################################################################  ## outputs  ######################################################################## -#for $i, $o in ((0, 0), (1, 1), (2, 2), (3, 3)) -power_down_lvpecl_out$i        $hex(0x3C+$o)[0:1]  0   normal, test, safe_pd, total_pd -output_level_lvpecl_out$i      $hex(0x3C+$o)[2:3]  2   500mv, 340mv, 810mv, 660mv -#end for -#for $i, $o in ((4, 0), (5, 1), (6, 2), (7, 3)) -power_down_lvds_cmos_out$i     $hex(0x40+$o)[0]    0 -output_level_lvds_out$i        $hex(0x40+$o)[1:2]  1   1_75ma, 3_5ma, 5_25ma, 7ma -lvds_cmos_select_out$i         $hex(0x40+$o)[3]    1   lvds, cmos -inverted_cmos_driver_out$i     $hex(0x40+$o)[4]    0   dis, enb -#end for +% for i, o in ((0, 0), (1, 1), (2, 2), (3, 3)): +power_down_lvpecl_out${i}        ${hex(0x3C+o)}[0:1]  0   normal, test, safe_pd, total_pd +output_level_lvpecl_out${i}      ${hex(0x3C+o)}[2:3]  2   500mv, 340mv, 810mv, 660mv +% endfor +% for i, o in ((4, 0), (5, 1), (6, 2), (7, 3)): +power_down_lvds_cmos_out${i}     ${hex(0x40+o)}[0]    0 +output_level_lvds_out${i}        ${hex(0x40+o)}[1:2]  1   1_75ma, 3_5ma, 5_25ma, 7ma +lvds_cmos_select_out${i}         ${hex(0x40+o)}[3]    1   lvds, cmos +inverted_cmos_driver_out${i}     ${hex(0x40+o)}[4]    0   dis, enb +% endfor  clock_select                 0x45[0]               1   clk2_drives, clk1_drives  clk1_power_down              0x45[1]               0  clk2_power_down              0x45[2]               0 @@ -82,15 +82,15 @@ all_clock_inputs_pd          0x45[5]               0  ########################################################################  ## dividers  ######################################################################## -#for $i, $o in ((0, 0), (1, 2), (2, 4), (3, 6), (4, 8), (5, 10), (6, 12), (7, 14)) -divider_high_cycles_out$i      $hex(0x48+$o)[0:3]  0 -divider_low_cycles_out$i       $hex(0x48+$o)[4:7]  0 -phase_offset_out$i             $hex(0x49+$o)[0:3]  0 -start_out$i                    $hex(0x49+$o)[4]    0 -force_out$i                    $hex(0x49+$o)[5]    0 -nosync_out$i                   $hex(0x49+$o)[6]    0 -bypass_divider_out$i           $hex(0x49+$o)[7]    0 -#end for +% for i, o in ((0, 0), (1, 2), (2, 4), (3, 6), (4, 8), (5, 10), (6, 12), (7, 14)): +divider_high_cycles_out${i}      ${hex(0x48+o)}[0:3]  0 +divider_low_cycles_out${i}       ${hex(0x48+o)}[4:7]  0 +phase_offset_out${i}             ${hex(0x49+o)}[0:3]  0 +start_out${i}                    ${hex(0x49+o)}[4]    0 +force_out${i}                    ${hex(0x49+o)}[5]    0 +nosync_out${i}                   ${hex(0x49+o)}[6]    0 +bypass_divider_out${i}           ${hex(0x49+o)}[7]    0 +% endfor  ########################################################################  ## function  ######################################################################## @@ -110,13 +110,13 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint16_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py index 1512da811..cc906b76c 100755 --- a/host/lib/ic_reg_maps/gen_ad9522_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2010-2011,2015 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 @@ -88,39 +88,38 @@ ref2_freq_gt_thresh         0x01F[2]                 0  ref1_freq_gt_thresh         0x01F[1]                 0  digital_lock_detect         0x01F[0]                 0  ######################################################################## -#for $i in range(12) -#set $addr = ($i + 0x0F0) -out$(i)_format              $(addr)[7]             0             lvds, cmos -out$(i)_cmos_configuration  $(addr)[6:5]           3             off, a_on, b_on, ab_on -out$(i)_polarity            $(addr)[4:3]           0             lvds_a_non_b_inv=0, lvds_a_inv_b_non=1, cmos_ab_non=0, cmos_ab_inv=1, cmos_a_non_b_inv=2, cmos_a_inv_b_non=3 -out$(i)_lvds_diff_voltage   $(addr)[2:1]           1             1_75ma, 3_5ma, 5_25ma, 7_0ma -out$(i)_lvds_power_down     $(addr)[0]             0 -#end for +% for i in range(12): +<% addr = (i + 0x0F0) %>\ +out${i}_format              ${addr}[7]             0             lvds, cmos +out${i}_cmos_configuration  ${addr}[6:5]           3             off, a_on, b_on, ab_on +out${i}_polarity            ${addr}[4:3]           0             lvds_a_non_b_inv=0, lvds_a_inv_b_non=1, cmos_ab_non=0, cmos_ab_inv=1, cmos_a_non_b_inv=2, cmos_a_inv_b_non=3 +out${i}_lvds_diff_voltage   ${addr}[2:1]           1             1_75ma, 3_5ma, 5_25ma, 7_0ma +out${i}_lvds_power_down     ${addr}[0]             0 +% endfor  ######################################################################## -#for $i in reversed(range(8)) -csdld_en_out_$i             0x0FC[$i]                0           ignore, async -#end for +% for i in reversed(range(8)): +csdld_en_out_${i}           0x0FC[${i}]                0           ignore, async +% endfor  ######################################################################## -#for $i in reversed(range(4)) -csdld_en_out_$(8 + $i)      0x0FD[$i]                0           ignore, async -#end for +% for i in reversed(range(4)): +csdld_en_out_${8 + i}      0x0FD[${i}]                0           ignore, async +% endfor  ######################################################################## -#set $default_val = 0x7 -#for $i in range(4) -#set $addr0 = hex($i*3 + 0x190) -#set $addr1 = hex($i*3 + 0x191) -#set $addr2 = hex($i*3 + 0x192) -divider$(i)_low_cycles      $(addr0)[7:4]         $default_val -divider$(i)_high_cycles     $(addr0)[3:0]         $default_val -divider$(i)_bypass          $(addr1)[7]           0 -divider$(i)_ignore_sync     $(addr1)[6]           0 -divider$(i)_force_high      $(addr1)[5]           0 -divider$(i)_start_high      $(addr1)[4]           0 -divider$(i)_phase_offset    $(addr1)[3:0]         0 -channel$(i)_power_down      $(addr2)[2]           0 -disable_divider$(i)_ddc     $(addr2)[0]           0 -#set $default_val /= 2 -#end for +% for i in range(4): +<% default_val = int(0x7 / (2**i)) %>\ +<% addr0 = hex(i*3 + 0x190) %>\ +<% addr1 = hex(i*3 + 0x191) %>\ +<% addr2 = hex(i*3 + 0x192) %>\ +divider${i}_low_cycles      ${addr0}[7:4]         ${default_val} +divider${i}_high_cycles     ${addr0}[3:0]         ${default_val} +divider${i}_bypass          ${addr1}[7]           0 +divider${i}_ignore_sync     ${addr1}[6]           0 +divider${i}_force_high      ${addr1}[5]           0 +divider${i}_start_high      ${addr1}[4]           0 +divider${i}_phase_offset    ${addr1}[3:0]         0 +channel${i}_power_down      ${addr2}[2]           0 +disable_divider${i}_ddc     ${addr2}[0]           0 +% endfor  ########################################################################  vco_divider                  0x1E0[2:0]              2             div2, div3, div4, div5, div6, static, div1  power_down_clock_input_sel   0x1E1[4]                0 @@ -145,13 +144,13 @@ BODY_TMPL="""\  boost::uint32_t get_reg(boost::uint16_t addr){      boost::uint32_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      if (addr == 0){ //mirror 4 bits in register 0          reg |= ((reg >> 7) & 0x1) << 0; @@ -164,13 +163,13 @@ boost::uint32_t get_reg(boost::uint16_t addr){  void set_reg(boost::uint16_t addr, boost::uint32_t reg){      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +        % endfor          break; -    #end for +    % endfor      }  } diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py index 47b61cf44..514283409 100755 --- a/host/lib/ic_reg_maps/gen_ad9777_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py @@ -91,13 +91,13 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py index 00340224c..022d97c16 100755 --- a/host/lib/ic_reg_maps/gen_ad9862_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py @@ -41,10 +41,10 @@ all_rx_pd          1[0]              0  ########################################################################  ## Rx A and B  ######################################################################## -#for $x, $i in (('a', 2), ('b', 3)) -byp_buffer_$x      $(i)[7]           0 -rx_pga_$x          $(i)[0:4]         0 -#end for +% for x, i in (('a', 2), ('b', 3)): +byp_buffer_${x}      ${i}[7]           0 +rx_pga_${x}          ${i}[0:4]         0 +% endfor  ########################################################################  ## Rx Misc  ######################################################################## @@ -76,13 +76,13 @@ tx_analog_pd       8[0:2]            0        none=0, txb=4, txa=2, both=7  ########################################################################  ## Tx Offset and Gain  ######################################################################## -#for $x, $i, $j, $k in (('a', 10, 11, 14), ('b', 12, 13, 15)) -dac_$(x)_offset_1_0   $(i)[6:7]           0 -dac_$(x)_offset_dir   $(i)[0]             0        neg_diff, pos_dif -dac_$(x)_offset_9_2   $(j)[0:7]           0 -dac_$(x)_coarse_gain  $(k)[6:7]           0 -dac_$(x)_fine_gain    $(k)[0:5]           0 -#end for +% for x, i, j, k in (('a', 10, 11, 14), ('b', 12, 13, 15)): +dac_${x}_offset_1_0   ${i}[6:7]           0 +dac_${x}_offset_dir   ${i}[0]             0        neg_diff, pos_dif +dac_${x}_offset_9_2   ${j}[0:7]           0 +dac_${x}_coarse_gain  ${k}[6:7]           0 +dac_${x}_fine_gain    ${k}[0:5]           0 +% endfor  tx_pga_gain            16[0:7]            0  ########################################################################  ## Tx Misc @@ -139,20 +139,20 @@ dis1                   25[0]              0       enb, dis  ########################################################################  ## Aux ADC  ######################################################################## -#for $x, $i in (('a2', 26), ('a1', 28), ('b2', 30), ('b1', 32)) -aux_adc_$(x)_1_0       $(i)[6:7]          0 -aux_adc_$(x)_9_2       $int(1+$i)[0:7]    0 -#end for +% for x, i in (('a2', 26), ('a1', 28), ('b2', 30), ('b1', 32)): +aux_adc_${x}_1_0       ${i}[6:7]          0 +aux_adc_${x}_9_2       ${int(1+i)}[0:7]    0 +% endfor  ########################################################################  ## Aux ADC Control  ########################################################################  aux_spi                34[7]              0       dis, enb  sel_bnota              34[6]              0       adc_a, adc_b -#for $x, $i in (('b', 5), ('a', 2)) -refsel_$(x)            34[$i]             0       external, internal -select_$(x)            34[$int($i-1)]     0       aux_adc2, aux_adc1 -start_$(x)             34[$int($i-2)]     0 -#end for +% for x, i in (('b', 5), ('a', 2)): +refsel_${x}            34[${i}]           0       external, internal +select_${x}            34[${int(i-1)}]    0       aux_adc2, aux_adc1 +start_${x}             34[${int(i-2)}]    0 +% endfor  ########################################################################  ## Aux ADC Clock  ######################################################################## @@ -160,9 +160,9 @@ clk_4                  35[0]              0       1_2, 1_4  ########################################################################  ## Aux DAC  ######################################################################## -#for $x, $i in (('a', 36), ('b', 37), ('c', 38)) -aux_dac_$x             $(i)[0:7]          0 -#end for +% for x, i in (('a', 36), ('b', 37), ('c', 38)): +aux_dac_${x}           ${i}[0:7]          0 +% endfor  ########################################################################  ## Aux DAC Update  ######################################################################## @@ -205,26 +205,26 @@ BODY_TMPL="""  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in range(0, 63+1) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in range(0, 63+1): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint16_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  }  void set_reg(boost::uint8_t addr, boost::uint16_t reg){      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +        % endfor          break; -    #end for +    % endfor      }  } diff --git a/host/lib/ic_reg_maps/gen_adf4350_regs.py b/host/lib/ic_reg_maps/gen_adf4350_regs.py index fce2f569b..644654dee 100755 --- a/host/lib/ic_reg_maps/gen_adf4350_regs.py +++ b/host/lib/ic_reg_maps/gen_adf4350_regs.py @@ -43,8 +43,8 @@ power_down              2[5]        0       disabled, enabled  pd_polarity             2[6]        1       negative, positive  ldp                     2[7]        0       10ns, 6ns  ldf                     2[8]        0       frac_n, int_n -#set $current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(round(x*31.27 + 31.27)/100)).split('.')), range(0,16))) -charge_pump_current     2[9:12]     5       $current_setting_enums +<% current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(round(x*31.27 + 31.27)/100)).split('.')), range(0,16))) %>\ +charge_pump_current     2[9:12]     5       ${current_setting_enums}  double_buffer           2[13]       0       disabled, enabled  r_counter_10_bit        2[14:23]    0  reference_divide_by_2   2[24]       1       disabled, enabled @@ -101,13 +101,13 @@ enum addr_t{  boost::uint32_t get_reg(boost::uint8_t addr){      boost::uint32_t reg = addr & 0x7;      switch(addr){ -    #for $addr in range(5+1) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in range(5+1): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_adf4351_regs.py b/host/lib/ic_reg_maps/gen_adf4351_regs.py index 4b0ef788c..6699e5137 100755 --- a/host/lib/ic_reg_maps/gen_adf4351_regs.py +++ b/host/lib/ic_reg_maps/gen_adf4351_regs.py @@ -44,8 +44,8 @@ power_down              2[5]        0       disabled, enabled  pd_polarity             2[6]        1       negative, positive  ldp                     2[7]        0       10ns, 6ns  ldf                     2[8]        0       frac_n, int_n -#set $current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(round(x*31.27 + 31.27)/100)).split('.')), range(0,16))) -charge_pump_current     2[9:12]     5       $current_setting_enums +<% current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(round(x*31.27 + 31.27)/100)).split('.')), range(0,16))) %>\ +charge_pump_current     2[9:12]     5       ${current_setting_enums}  double_buffer           2[13]       0       disabled, enabled  r_counter_10_bit        2[14:23]    0  reference_divide_by_2   2[24]       1       disabled, enabled @@ -105,13 +105,13 @@ enum addr_t{  boost::uint32_t get_reg(boost::uint8_t addr){      boost::uint32_t reg = addr & 0x7;      switch(addr){ -    #for $addr in range(5+1) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in range(5+1): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py index 3fd8707a7..921f014ff 100755 --- a/host/lib/ic_reg_maps/gen_adf4360_regs.py +++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py @@ -32,9 +32,9 @@ charge_pump_output       0[9]       0          normal, 3state  cp_gain_0                0[10]      0          set1, set2  mute_till_ld             0[11]      0          dis, enb  output_power_level       0[12:13]   0          3_5ma, 5_0ma, 7_5ma, 11_0ma -#set $current_setting_enums = ', '.join(map(lambda x: x+"ma", "0_31 0_62 0_93 1_25 1_56 1_87 2_18 2_50".split())) -current_setting1         0[14:16]   0          $current_setting_enums -current_setting2         0[17:19]   0          $current_setting_enums +<% current_setting_enums = ', '.join(map(lambda x: x+"ma", "0_31 0_62 0_93 1_25 1_56 1_87 2_18 2_50".split())) %>\ +current_setting1         0[14:16]   0          ${current_setting_enums} +current_setting2         0[17:19]   0          ${current_setting_enums}  power_down               0[20:21]   0          normal_op=0, async_pd=1, sync_pd=3  prescaler_value          0[22:23]   0          8_9, 16_17, 32_33  ######################################################################## @@ -68,13 +68,13 @@ enum addr_t{  boost::uint32_t get_reg(addr_t addr){      boost::uint32_t reg = addr & 0x3;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_ads62p44_regs.py b/host/lib/ic_reg_maps/gen_ads62p44_regs.py index f0a84d940..df5c0c66c 100755 --- a/host/lib/ic_reg_maps/gen_ads62p44_regs.py +++ b/host/lib/ic_reg_maps/gen_ads62p44_regs.py @@ -95,13 +95,13 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_ads62p48_regs.py b/host/lib/ic_reg_maps/gen_ads62p48_regs.py index c38ce8ff1..fa5668d4f 100644..100755 --- a/host/lib/ic_reg_maps/gen_ads62p48_regs.py +++ b/host/lib/ic_reg_maps/gen_ads62p48_regs.py @@ -55,13 +55,13 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_lmk04816_regs.py b/host/lib/ic_reg_maps/gen_lmk04816_regs.py index e89a82671..d432ac706 100644..100755 --- a/host/lib/ic_reg_maps/gen_lmk04816_regs.py +++ b/host/lib/ic_reg_maps/gen_lmk04816_regs.py @@ -1,4 +1,4 @@ -#Copyright 2010 Ettus Research LLC +#Copyright 2010,2015 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 @@ address0		 0[0:4]     0  CLKout0_1_DIV	         0[5:15]    25            CLKout0_1_HS             0[16]      0            RESET                    0[17]      0          no_reset, reset -CLKout0_1_DDLY	         0[18:27]   0          five +CLKout0_1_DDLY	         0[18:27]   0            CLKout0_ADLY_SEL         0[28]      0          d_pd, d_ev_x, d_odd_y, d_both  CLKout1_ADLY_SEL	 0[29]      0          d_pd, d_ev_x, d_odd_y, d_both  Required_0		 0[30]      0          @@ -94,15 +94,15 @@ CLKout10_11_PD           5[31] 	    1	       normal, power_down  ########################################################################  ## address 6  ######################################################################## -#set $CLKoutX_TYPE_ENUMS = "p_down=0, LVDS=1, LVPECL_700mVpp=2, LVPECL_1200mVpp=3, LVPECL_1600mVpp=4, LVPECL_200mVpp=5, LVCMOS=6, LVCMOS_IN=7, LVCMOS_NN=8, LVCMOS_II=9, LVCMOS_LN=10, LVCMOS_LI=11, LVCMOS_NL=12, LVCMOS_IL=13, LVCMOS_LL=1" +<% CLKoutX_TYPE_ENUMS = "p_down=0, LVDS=1, LVPECL_700mVpp=2, LVPECL_1200mVpp=3, LVPECL_1600mVpp=4, LVPECL_200mVpp=5, LVCMOS=6, LVCMOS_IN=7, LVCMOS_NN=8, LVCMOS_II=9, LVCMOS_LN=10, LVCMOS_LI=11, LVCMOS_NL=12, LVCMOS_IL=13, LVCMOS_LL=1" %>\  address6		 6[0:4]     6            CLKout0_1_ADLY	         6[5:9]     0            Required_6_10	         6[10]      0            CLKout2_3_ADLY           6[11:15]   0          -CLKout0_TYPE	         6[16:19]   0       $(CLKoutX_TYPE_ENUMS) -CLKout1_TYPE             6[20:23]   0       $(CLKoutX_TYPE_ENUMS) -CLKout2_TYPE	         6[24:27]   0       $(CLKoutX_TYPE_ENUMS) -CLKout3_TYPE	         6[28:31]   0       $(CLKoutX_TYPE_ENUMS) +CLKout0_TYPE	         6[16:19]   0       ${CLKoutX_TYPE_ENUMS} +CLKout1_TYPE             6[20:23]   0       ${CLKoutX_TYPE_ENUMS} +CLKout2_TYPE	         6[24:27]   0       ${CLKoutX_TYPE_ENUMS} +CLKout3_TYPE	         6[28:31]   0       ${CLKoutX_TYPE_ENUMS}  ########################################################################  ## address 7  ######################################################################## @@ -110,21 +110,21 @@ address7	                 7[0:4]     7  CLKout4_5_ADLY	         7[5:9]     0            Required_7_10	         7[10]      0            CLKout6_7_ADLY           7[11:15]   0          -CLKout4_TYPE	         7[16:19]   0          $(CLKoutX_TYPE_ENUMS) -CLKout5_TYPE	         7[20:23]   0          $(CLKoutX_TYPE_ENUMS) -CLKout6_TYPE	         7[24:27]   0          $(CLKoutX_TYPE_ENUMS) -CLKout7_TYPE	         7[28:31]   0          $(CLKoutX_TYPE_ENUMS) +CLKout4_TYPE	         7[16:19]   0          ${CLKoutX_TYPE_ENUMS} +CLKout5_TYPE	         7[20:23]   0          ${CLKoutX_TYPE_ENUMS} +CLKout6_TYPE	         7[24:27]   0          ${CLKoutX_TYPE_ENUMS} +CLKout7_TYPE	         7[28:31]   0          ${CLKoutX_TYPE_ENUMS}  ########################################################################  ## address 8  ########################################################################  address8		 8[0:4]     8            CLKout8_9_ADLY	         8[5:9]     0            Required_8_10	         8[10]      0           -CLKout10_11_ADLY         8[11:15]   0          $(CLKoutX_TYPE_ENUMS) -CLKout8_TYPE	         8[16:19]   0          $(CLKoutX_TYPE_ENUMS) -CLKout9_TYPE	         8[20:23]   0          $(CLKoutX_TYPE_ENUMS) -CLKout10_TYPE	         8[24:27]   0          $(CLKoutX_TYPE_ENUMS) -CLKout11_TYPE	         8[28:31]   0          $(CLKoutX_TYPE_ENUMS) +CLKout10_11_ADLY         8[11:15]   0          ${CLKoutX_TYPE_ENUMS} +CLKout8_TYPE	         8[16:19]   0          ${CLKoutX_TYPE_ENUMS} +CLKout9_TYPE	         8[20:23]   0          ${CLKoutX_TYPE_ENUMS} +CLKout10_TYPE	         8[24:27]   0          ${CLKoutX_TYPE_ENUMS} +CLKout11_TYPE	         8[28:31]   0          ${CLKoutX_TYPE_ENUMS}  ########################################################################  ## address 9  ######################################################################## @@ -378,22 +378,18 @@ BODY_TMPL = """\  boost::uint32_t get_reg(int addr){      boost::uint32_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  }  """ - - - -  if __name__ == '__main__':      import common; common.generate(          name='lmk04816_regs', @@ -402,6 +398,3 @@ if __name__ == '__main__':          file=__file__,      ) - - -             diff --git a/host/lib/ic_reg_maps/gen_max2112_regs.py b/host/lib/ic_reg_maps/gen_max2112_regs.py index c2fc4e3e2..be760ec2e 100755 --- a/host/lib/ic_reg_maps/gen_max2112_regs.py +++ b/host/lib/ic_reg_maps/gen_max2112_regs.py @@ -53,13 +53,14 @@ f_divider_lsb         4[0:7]        0x84  ########################################################################  ## XTAL-Divider R-Divider (5) Write  ######################################################################## -#set $xtal_divider_names = ', '.join(map(lambda x: 'div' + str(x), range(1,9))) -xtal_divider          5[5:7]        0       $xtal_divider_names +<% xtal_divider_names = ', '.join(map(lambda x: 'div' + str(x), range(1,9))) %>\ +xtal_divider          5[5:7]        0       ${xtal_divider_names}  r_divider             5[0:4]        1         ########################################################################  ## PLL (6) Write  ######################################################################## -d24                   6[7]          1       div2, div4  ## div2 for LO <= 1125M, div4 > 1125M +## div2 for LO <= 1125M, div4 > 1125M +d24                   6[7]          1       div2, div4  cps                   6[6]          1       i_cp_from_icp, i_cp_from_vas  icp                   6[5]          0       i_cp_600ua, i_cp_1200ua  ##reserved            6[0:4]        0 @@ -73,7 +74,8 @@ ade                   7[0]          1       disabled, enabled  ########################################################################  ## LPF (8) Write  ######################################################################## -lp                    8[0:7]        0x4B    ## map(lambda x: "%0.2f"%((4e6 + (x - 12) * 290e3)/1e6), range(255)) in MHz +## map(lambda x: "%0.2f"%((4e6 + (x - 12) * 290e3)/1e6), range(255)) in MHz +lp                    8[0:7]        0x4B  ########################################################################  ## Control (9) Write  ######################################################################## @@ -81,7 +83,8 @@ stby                  9[7]          0       normal, disable_sig_and_synth  ##reserved            9[6]          0  pwdn                  9[5]          0       normal, invalid  ##reserved            9[4]          0 -bbg                   9[0:3]        0       ## Baseband Gain in dB +## Baseband Gain in dB +bbg                   9[0:3]        0  ########################################################################  ## Shutdown (0xA) Write  ######################################################################## @@ -118,7 +121,8 @@ ld                    0xC[4]        0       unlocked, locked  ########################################################################  ## Status Byte-2 (0xD) Read  ######################################################################## -vcosbr                0xD[3:7]      0       ## vco band readback +## vco band readback +vcosbr                0xD[3:7]      0         adc                   0xD[0:2]      0       ool0, lock0, vaslock0, vaslock1, vaslock2, vaslock3, lock1, ool1  """ @@ -129,41 +133,30 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return boost::uint8_t(reg);  }  void set_reg(boost::uint8_t addr, boost::uint8_t reg){      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +        % endfor          break; -    #end for +    % endfor      }  }  """ -SPLIT_REGS_HELPER_TMPL="""\ -#for $divname in ['n','f'] -void set_$(divname)_divider(boost::uint32_t $divname){ -    #for $regname in sorted(map(lambda r: r.get_name(), filter(lambda r: r.get_name().find(divname + '_divider') == 0, $regs))) -    #end for -} -#end for -""" -    #$regname = boost::uint8_t($divname & $regs[regname].get_mask()); -    #$divname = boost::uint32_t($divname >> $regs[regname].get_shift()); -  if __name__ == '__main__':      import common; common.generate(          name='max2112_write_regs', diff --git a/host/lib/ic_reg_maps/gen_max2118_regs.py b/host/lib/ic_reg_maps/gen_max2118_regs.py index 506fbaec8..01d7615de 100755 --- a/host/lib/ic_reg_maps/gen_max2118_regs.py +++ b/host/lib/ic_reg_maps/gen_max2118_regs.py @@ -38,28 +38,31 @@ n_divider_lsb         1[0:7]        0xB6  ########################################################################  ## R, Charge Pump, and VCO (2) Write  ######################################################################## -#set $r_divider_names = ', '.join(map(lambda x: 'div' + str(2**(x+1)), range(0,8))) -r_divider             2[5:7]        1       $r_divider_names  -#set $cp_current_bias = ', '.join(map(lambda x: 'i_cp_%dua'%(50*2**x), range(0,4))) -cp_current            2[3:4]        3       $cp_current_bias +<% r_divider_names = ', '.join(map(lambda x: 'div' + str(2**(x+1)), range(0,8))) %>\ +r_divider             2[5:7]        1       ${r_divider_names} +<% cp_current_bias = ', '.join(map(lambda x: 'i_cp_%dua'%(50*2**x), range(0,4))) %>\ +cp_current            2[3:4]        3       ${cp_current_bias}  osc_band              2[0:2]        5  ########################################################################  ## I/Q Filter DAC (3) Write  ########################################################################  ##unused              3[7]          0 -f_dac                 3[0:6]        0x7F    ## filter tuning dac, depends on m +## filter tuning dac, depends on m +f_dac                 3[0:6]        0x7F  ########################################################################  ## LPF Divider DAC (4) Write  ########################################################################  adl_vco_adc_latch     4[7]          0       disabled, enabled  ade_vco_ade_read      4[6]          0       disabled, enabled  dl_output_drive       4[5]          0       iq_590m_vpp, iq_1_vpp -m_divider             4[0:4]        2       ## filter tuning counter +## filter tuning counter +m_divider             4[0:4]        2  ########################################################################  ## GC2 and Diag (5) Write  ########################################################################  diag                  5[5:7]        0       normal, cp_i_source, cp_i_sink, cp_high_z, unused, n_and_filt, r_and_gc2, m_div -gc2                   5[0:4]        0x1F    ## Step Size: 0-1: 0dB, 2-22: 1dB, 23-31: 0.5dB +## Step Size: 0-1: 0dB, 2-22: 1dB, 23-31: 0.5dB +gc2                   5[0:4]        0x1F  """  ######################################################################## @@ -71,11 +74,13 @@ READ_REGS_TMPL="""\  ## Status (0) Read  ########################################################################  pwr                   0[6]          0       not_reset, reset -adc                   0[2:4]        0       ## VCO tuning voltage, Lock Status +## VCO tuning voltage, Lock Status +adc                   0[2:4]        0  ########################################################################  ## I/Q Filter DAC (1) Read  ######################################################################## -filter_dac            1[0:6]        0       ## I/Q Filter tuning DAC, current +## I/Q Filter tuning DAC, current +filter_dac            1[0:6]        0  """  ######################################################################## @@ -85,26 +90,26 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return boost::uint8_t(reg);  }  void set_reg(boost::uint8_t addr, boost::uint8_t reg){      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +        % endfor          break; -    #end for +    % endfor      }  }  """ diff --git a/host/lib/ic_reg_maps/gen_max2829_regs.py b/host/lib/ic_reg_maps/gen_max2829_regs.py index 383131c18..dbcb68ec9 100755 --- a/host/lib/ic_reg_maps/gen_max2829_regs.py +++ b/host/lib/ic_reg_maps/gen_max2829_regs.py @@ -112,13 +112,13 @@ BODY_TMPL="""\  boost::uint32_t get_reg(boost::uint8_t addr){      boost::uint16_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint16_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return (boost::uint32_t(reg) << 4) | (addr & 0xf);  } diff --git a/host/lib/ic_reg_maps/gen_max2870_regs.py b/host/lib/ic_reg_maps/gen_max2870_regs.py index f26c27281..af4e3c786 100644..100755 --- a/host/lib/ic_reg_maps/gen_max2870_regs.py +++ b/host/lib/ic_reg_maps/gen_max2870_regs.py @@ -28,8 +28,10 @@ REGS_TMPL="""\  ## Write-only, default = 0x007D0000  ########################################################################  int_n_mode              0x00[31]        0       frac_n, int_n -int_16_bit              0x00[15:30]     0x007D  ##Integer divider: 16-65535 in int-N mode, 19-4091 in frac-N mode. -frac_12_bit             0x00[3:14]      0       ##Frac divider: 0-4095 +## Integer divider: 16-65535 in int-N mode, 19-4091 in frac-N mode. +int_16_bit              0x00[15:30]     0x007D +## Frac divider: 0-4095 +frac_12_bit             0x00[3:14]      0  ########################################################################  ## Address 0x01  ## Charge pump control @@ -38,8 +40,10 @@ frac_12_bit             0x00[3:14]      0       ##Frac divider: 0-4095  cpoc                    0x01[31]        0       disabled, enabled  cpl                     0x01[29:30]     1       disabled, enabled, res1, res2  cpt                     0x01[27:28]     0       normal, reserved, force_source, force_sink -phase_12_bit            0x01[15:26]     1       ##sets phase shift -mod_12_bit              0x01[3:14]      0xFFF   ##VCO frac modulus +## sets phase shift +phase_12_bit            0x01[15:26]     1 +## VCO frac modulus +mod_12_bit              0x01[3:14]      0xFFF  ########################################################################  ## Address 0x02  ## Misc. control @@ -50,10 +54,11 @@ low_noise_and_spur      0x02[29:30]     3       low_noise, reserved, low_spur_1,  muxout                  0x02[26:28]     1       tri_state, high, low, rdiv, ndiv, ald, dld, res7  reference_doubler       0x02[25]        0       disabled, enabled  reference_divide_by_2   0x02[24]        0       disabled, enabled -r_counter_10_bit        0x02[14:23]     1       ##R divider value, 1-1023 +## R divider value, 1-1023 +r_counter_10_bit        0x02[14:23]     1  double_buffer           0x02[13]        0       disabled, enabled -#set $current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(1.631/5.1 * (1.+x))).split('.')), range(0,16))) -charge_pump_current     0x02[9:12]      7       $current_setting_enums +<% current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(1.631/5.1 * (1.+x))).split('.')), range(0,16))) %>\ +charge_pump_current     0x02[9:12]      7       ${current_setting_enums}  ldf                     0x02[8]         0       frac_n, int_n  ldp                     0x02[7]         0       10ns, 6ns  pd_polarity             0x02[6]         1       negative, positive @@ -65,18 +70,22 @@ counter_reset           0x02[3]         0       normal, reset  ## VCO control  ## Write-only, default = 0x0000000B  ######################################################################## -vco                     0x03[26:31]     0       ##VCO subband selection, used when VAS disabledd -vas                     0x03[25]        0       enabled, disabled ##VCO autoselect +## VCO subband selection, used when VAS disabledd +vco                     0x03[26:31]     0 +## VCO autoselect +vas                     0x03[25]        0       enabled, disabled  retune                  0x03[24]        1       disabled, enabled  clock_div_mode          0x03[15:16]     0       clock_divider_off, fast_lock, phase, reserved -clock_divider_12_bit    0x03[3:14]      1       ##clock divider, 1-4095 +## clock divider, 1-4095 +clock_divider_12_bit    0x03[3:14]      1  ########################################################################  ## Address 0x04  ## RF output control  ## Write-only, default = 0x6180B23C  ########################################################################  res4                    0x04[26:31]     0x18 -bs_msb                  0x04[24:25]     0       ##Band select MSBs +## Band select MSBs +bs_msb                  0x04[24:25]     0  feedback_select         0x04[23]        1       divided, fundamental  rf_divider_select       0x04[20:22]     0       div1, div2, div4, div8, div16, div32, div64, div128  band_select_clock_div   0x04[12:19]     0 @@ -111,13 +120,13 @@ enum addr_t{  boost::uint32_t get_reg(boost::uint8_t addr){      boost::uint32_t reg = addr & 0x7;      switch(addr){ -    #for $addr in range(5+1) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in range(5+1): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_max2871_regs.py b/host/lib/ic_reg_maps/gen_max2871_regs.py index 338a019d8..f591c1636 100644..100755 --- a/host/lib/ic_reg_maps/gen_max2871_regs.py +++ b/host/lib/ic_reg_maps/gen_max2871_regs.py @@ -28,8 +28,10 @@ REGS_TMPL="""\  ## Write-only, default = 0x007D0000  ########################################################################  int_n_mode              0x00[31]        0       frac_n, int_n -int_16_bit              0x00[15:30]     0x007D  ##Integer divider: 16-65535 in int-N mode, 19-4091 in frac-N mode. -frac_12_bit             0x00[3:14]      0       ##Frac divider: 0-4095 +## Integer divider: 16-65535 in int-N mode, 19-4091 in frac-N mode. +int_16_bit              0x00[15:30]     0x007D +## Frac divider: 0-4095 +frac_12_bit             0x00[3:14]      0  ########################################################################  ## Address 0x01  ## Charge pump control @@ -38,8 +40,10 @@ frac_12_bit             0x00[3:14]      0       ##Frac divider: 0-4095  res1                    0x01[31]        0  cpl                     0x01[29:30]     1       disabled, enabled, res1, res2  cpt                     0x01[27:28]     0       normal, reserved, force_source, force_sink -phase_12_bit            0x01[15:26]     1       ##sets phase shift -mod_12_bit              0x01[3:14]      0xFFF   ##VCO frac modulus +## sets phase shift +phase_12_bit            0x01[15:26]     1 +## VCO frac modulus +mod_12_bit              0x01[3:14]      0xFFF  ########################################################################  ## Address 0x02  ## Misc. control @@ -50,10 +54,11 @@ low_noise_and_spur      0x02[29:30]     3       low_noise, reserved, low_spur_1,  muxout                  0x02[26:28]     0x6     tri_state, high, low, rdiv, ndiv, ald, dld, sync, res8, res9, res10, res11, spi, res13, res14, res15  reference_doubler       0x02[25]        0       disabled, enabled  reference_divide_by_2   0x02[24]        0       disabled, enabled -r_counter_10_bit        0x02[14:23]     1       ##R divider value, 1-1023 +## R divider value, 1-1023 +r_counter_10_bit        0x02[14:23]     1  double_buffer           0x02[13]        0       disabled, enabled -#set $current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(1.631/5.1 * (1.+x))).split('.')), range(0,16))) -charge_pump_current     0x02[9:12]      7       $current_setting_enums +<% current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(1.631/5.1 * (1.+x))).split('.')), range(0,16))) %>\ +charge_pump_current     0x02[9:12]      7       ${current_setting_enums}  ldf                     0x02[8]         0       frac_n, int_n  ldp                     0x02[7]         0       10ns, 6ns  pd_polarity             0x02[6]         1       negative, positive @@ -65,14 +70,17 @@ counter_reset           0x02[3]         0       normal, reset  ## VCO control  ## Write-only, default = 0x0000000B  ######################################################################## -vco                     0x03[26:31]     0       ##VCO subband selection, used when VAS disabledd -shutdown_vas            0x03[25]        0       enabled, disabled ##VCO autoselect +## VCO subband selection, used when VAS disabledd +vco                     0x03[26:31]     0 +## VCO autoselect +shutdown_vas            0x03[25]        0       enabled, disabled  retune                  0x03[24]        1       disabled, enabled  res3                    0x3[19:23]      0  csm                     0x3[18]         0       disabled, enabled  mutedel                 0x3[17]         0       disabled, enabled  clock_div_mode          0x03[15:16]     0       clock_divider_off, fast_lock, phase, reserved -clock_divider_12_bit    0x03[3:14]      1       ##clock divider, 1-4095 +## clock divider, 1-4095 +clock_divider_12_bit    0x03[3:14]      1  ########################################################################  ## Address 0x04  ## RF output control @@ -82,7 +90,8 @@ res4                    0x04[29:31]     0x3  shutdown_ldo            0x04[28]        0       enabled, disabled  shutdown_div            0x04[27]        0       enabled, disabled  shutdown_ref            0x04[26]        0       enabled, disabled -bs_msb                  0x04[24:25]     0       ##Band select MSBs +## Band select MSBs +bs_msb                  0x04[24:25]     0  feedback_select         0x04[23]        1       divided, fundamental  rf_divider_select       0x04[20:22]     0       div1, div2, div4, div8, div16, div32, div64, div128  band_select_clock_div   0x04[12:19]     0 @@ -124,13 +133,13 @@ enum addr_t{  boost::uint32_t get_reg(boost::uint8_t addr){      boost::uint32_t reg = addr & 0x7;      switch(addr){ -    #for $addr in range(5+1) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in range(5+1): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return reg;  } diff --git a/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py b/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py index 677a201de..308d7d524 100755 --- a/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py +++ b/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py @@ -28,7 +28,7 @@ REGS_TMPL="""\  ########################################################################  ##  ID_byte_1 (0x00) Read  ######################################################################## -##reserved as 1       0x00[7]       1 +## reserved as 1       0x00[7]       1  ident_14_8            0x00[0:6]     0  ########################################################################  ##  ID_byte_2 (0x01) Read @@ -43,23 +43,25 @@ minor_rev             0x02[0:3]     0  ########################################################################  ##  Thermo_byte_1 (0x03) Read  ######################################################################## -##reserved            0x03[7]       0 -tm_d                  0x03[0:6]     0   ## 22-127deg C junction temp +## reserved            0x03[7]       0 +## 22-127deg C junction temp +tm_d                  0x03[0:6]     0  ########################################################################  ##  Thermo_byte_2 (0x04) Write  ######################################################################## -##reserved            0x04[1:7]     0 +## reserved            0x04[1:7]     0  tm_on                 0x04[0]       0   sensor_off, sensor_on  ########################################################################  ##  Power_state_byte_1 (0x05) Read  ######################################################################## -##reserved            0x05[2:7]     0 +## reserved            0x05[2:7]     0  por                   0x05[1]       0   read, reset  lo_lock               0x05[0]       0   unlocked, locked  ######################################################################## -##  Power_state_byte_2 (0x06) Read/Write ## Standby modes +## Standby modes +##  Power_state_byte_2 (0x06) Read/Write  ######################################################################## -##reserved            0x06[4:7]     0 +## reserved            0x06[4:7]     0  sm                    0x06[3]       0   normal, standby  sm_pll                0x06[2]       0   on, off  sm_lna                0x06[1]       0   on, off @@ -68,14 +70,15 @@ sm_lna                0x06[1]       0   on, off  ########################################################################  ##  Input_Power_Level_byte (0x07) Read  ######################################################################## -##reserved            0x07[7]       0 -power_level           0x07[0:6]     0   ## 40dB_Vrms to 110dB_Vrms +## reserved            0x07[7]       0 +## 40dB_Vrms to 110dB_Vrms +power_level           0x07[0:6]     0  ## Trigger power level calculation with MSM_byte_1 and MSM_byte_2  ########################################################################  ##  IRQ_status (0x08) Read/Write  ########################################################################  irq_status            0x08[7]       0   cleared, set -##reserved            0x08[6]       0 +## reserved            0x08[6]       0  irq_xtalcal_end       0x08[5]       0   false, true  irq_rssi_end          0x08[4]       0   false, true  irq_localc_end        0x08[3]       0   false, true @@ -86,7 +89,7 @@ irq_rccal_end         0x08[0]       0   false, true  ##  IRQ_enable (0x09) Read/Write  ########################################################################  irq_enable            0x09[7]       1   false, true -##reserved            0x09[6]       0 +## reserved            0x09[6]       0  irq_xtalcal_enable    0x09[5]       0   false, true  irq_rssi_enable       0x09[4]       0   false, true  irq_localc_enable     0x09[3]       0   false, true @@ -97,7 +100,7 @@ irq_rccal_enable      0x09[0]       0   false, true  ##  IRQ_clear (0x0a) Read/Write  ########################################################################  irq_clear             0x0a[7]       0   false, true -##reserved            0x0a[6]       0 +## reserved            0x0a[6]       0  irq_xtalcal_clear     0x0a[5]       0   false, true  irq_rssi_clear        0x0a[4]       0   false, true  irq_localc_clear      0x0a[3]       0   false, true @@ -108,7 +111,7 @@ irq_rccal_clear       0x0a[0]       0   false, true  ##  IRQ_set (0x0b) Read  ########################################################################  irq_set               0x0b[7]       0   false, true -##reserved            0x0b[6]       0 +## reserved            0x0b[6]       0  irq_xtalcal_set       0x0b[5]       0   false, true  irq_rssi_set          0x0b[4]       0   false, true  irq_localc_set        0x0b[3]       0   false, true @@ -120,12 +123,12 @@ irq_rccal_set         0x0b[0]       0   false, true  ########################################################################  lt_enable             0x0c[7]       0  agc1_6_15db           0x0c[6]       1 -##reserved            0x0c[4:5]     0 +## reserved            0x0c[4:5]     0  agc1_top              0x0c[0:3]     0  ########################################################################  ##  AGC2_byte_1 (0x0d) Read  ######################################################################## -##reserved            0x0d[5:7]     0 +## reserved            0x0d[5:7]     0  agc2_top              0x0d[0:4]     0xf  ########################################################################  ##  AGCK_byte_1 (0x0e) Read/Write @@ -141,24 +144,25 @@ agck_mode             0x0e[0:1]     1   analog_tv=1, digital_tv=2  pd_rfagc_adapt        0x0f[7]       0   on, off  rfagc_adapt_top       0x0f[5:6]     0  rfagc_low_bw          0x0f[4]       1 -rf_atten_3db          0x0f[3]       0   0db, 3db ## FIXME +## FIXME +rf_atten_3db          0x0f[3]       0   0db, 3db  agc3_top              0x0f[0:2]     1  ########################################################################  ##  IR_MIXER_byte_1 (0x10) Read/Write  ######################################################################## -##reserved            0x10[4:7]     0 +## reserved            0x10[4:7]     0  agc4_top              0x10[0:3]     1  ########################################################################  ##  AGC5_byte_1 (0x11) Read/Write  ######################################################################## -##reserved            0x11[7]       0 +## reserved            0x11[7]       0  agcs_do_step_assym    0x11[5:6]     2  agc5_hpf              0x11[4]       1   off, on  agc5_top              0x11[0:3]     1  ########################################################################  ##  IF_AGC_byte (0x12) Read/Write  ######################################################################## -##reserved            0x12[3:7]     0 +## reserved            0x12[3:7]     0  if_level              0x12[0:2]     0   0_5vpp=7, 0_6vpp=6, 0_7vpp=5, 0_85vpp=4, 0_8vpp=3, 1_0vpp=2, 1_25vpp=1, 2_0vpp=0  ########################################################################  ##  IF_byte_1 (0x13) Read/Write @@ -172,18 +176,19 @@ lp_fc                 0x13[0:2]     3   1_7mhz=4, 6_0mhz=0, 7_0mhz=1, 8_0mhz=2,  ########################################################################  i2c_clock_mode        0x14[7]       0  digital_clock         0x14[6]       1   spread_off, spread_on -##reserved            0x14[5]       0 +## reserved            0x14[5]       0  xtalosc_anareg_en     0x14[4]       0 -##reserved            0x14[2:3]     0 +## reserved            0x14[2:3]     0  xtout                 0x14[0:1]     0   no=0, 16mhz=3  ########################################################################  ##  IF_Frequency_byte (0x15) Read/Write  ######################################################################## -if_freq               0x15[0:7]     0   ## IF frequency = if_freq*50 (kHz) +## IF frequency = if_freq*50 (kHz) +if_freq               0x15[0:7]     0  ########################################################################  ##  RF_Frequency_byte_1 (0x16) Read/Write  ######################################################################## -##reserved            0x16[4:7]     0 +## reserved           0x16[4:7]     0  rf_freq_19_16         0x16[0:3]     0  ########################################################################  ##  RF_Frequency_byte_2 (0x17) Read/Write @@ -209,7 +214,7 @@ calc_pll              0x19[0]       0  ########################################################################  ##  MSM_byte_2 (0x1a) Read  ######################################################################## -##reserved            0x1a[2:7]     0 +## reserved           0x1a[2:7]     0  xtalcal_launch        0x1a[1]       0  msm_launch            0x1a[0]       0  ######################################################################## @@ -227,11 +232,11 @@ psm_lodriver          0x1b[0:1]     0  dcc_bypass            0x1c[7]       0  dcc_slow              0x1c[6]       0  dcc_psm               0x1c[5]       0 -##reserved            0x1c[0:4]     0 +## reserved           0x1c[0:4]     0  ########################################################################  ##  FLO_Max_byte (0x1d) Read  ######################################################################## -##reserved            0x1d[6:7]     0 +## reserved           0x1d[6:7]     0  fmax_lo               0x1d[0:5]     0xA  ########################################################################  ##  IR_Cal_byte_1 (0x1e) Read @@ -249,12 +254,12 @@ ir_freqlow            0x1f[0:4]     0  ########################################################################  ##  IR_Cal_byte_3 (0x20) Read  ######################################################################## -##reserved            0x20[5:7]     0 +## reserved           0x20[5:7]     0  ir_freqmid            0x20[0:4]     0  ########################################################################  ##  IR_Cal_byte_4 (0x21) Read  ######################################################################## -##reserved            0x21[5:7]     0 +## reserved           0x21[5:7]     0  coarse_ir_freqhigh    0x21[4]       0  ir_freqhigh           0x21[0:3]     0  ######################################################################## @@ -270,8 +275,9 @@ agc_ovld_timer        0x22[0:1]     0  ########################################################################  ir_mixer_loop_off     0x23[7]       0  ir_mixer_do_step      0x23[5:6]     0 -##reserved            0x23[2:4]     0 -hi_pass               0x23[1]       0   disable, enable ## FIXME Logic Unclear +## reserved            0x23[2:4]     0 +## FIXME Logic Unclear +hi_pass               0x23[1]       0   disable, enable  if_notch              0x23[0]       1   on, off  ########################################################################  ##  AGC1_byte_2 (0x24) Read @@ -285,9 +291,9 @@ agc1_gain             0x24[0:3]     8  ########################################################################  agc5_loop_off         0x25[7]       0  agc5_do_step          0x25[5:6]     0 -##reserved            0x25[4]       0 +## reserved            0x25[4]       0  force_agc5_gain       0x25[3]       0 -##reserved            0x25[2]       0 +## reserved            0x25[2]       0  agc5_gain             0x25[0:1]     2  ########################################################################  ##  RF_Cal_byte_1 (0x26) Read @@ -335,7 +341,7 @@ rfcal_freq11          0x2b[0:1]     0  ##  RF_Filter_byte_1 (0x2c) Read  ########################################################################  rf_filter_bypass      0x2c[7]       0 -##reserved as 0       0x2c[6]       0 +## reserved as 0       0x2c[6]       0  agc2_loop_off         0x2c[5]       0  force_agc2_gain       0x2c[4]       0  rf_filter_gv          0x2c[2:3]     2 @@ -353,12 +359,12 @@ gain_taper            0x2e[0:5]     0  ##  RF_Band_Pass_Filter_byte (0x2f) Read  ########################################################################  rf_bpf_bypass         0x2f[7]       0 -##reserved            0x2f[3:6]     0 +## reserved            0x2f[3:6]     0  rf_bpf                0x2f[0:2]     0  ########################################################################  ##  CP_Current_byte (0x30) Read  ######################################################################## -##reserved            0x30[7]       0 +## reserved            0x30[7]       0  n_cp_current          0x30[0:6]     0x68  ########################################################################  ##  AGC_Det_Out_byte (0x31) Read @@ -374,24 +380,26 @@ do_agc1               0x31[0]       0  ########################################################################  ##  RF_AGC_Gain_byte_1 (0x32) Read  ######################################################################## -#set $lna_gain_names = ', '.join(map(lambda x: {0: '', 1: 'm'}[3*x-12 < 0] + str(abs(3*x-12)) + 'db=' + str(x), range(0,10))) -##reserved            0x32[6:7]     0 +## reserved            0x32[6:7]     0  agc2_gain_read        0x32[4:5]     3   m11db, m8db, m5db, m2db -agc1_gain_read        0x32[0:3]     9   $lna_gain_names +<% lna_gain_names = ', '.join(map(lambda x: {0: '', 1: 'm'}[3*x-12 < 0] + str(abs(3*x-12)) + 'db=' + str(x), range(0,10))) %>\ +agc1_gain_read        0x32[0:3]     9   ${lna_gain_names}  ########################################################################  ##  RF_AGC_Gain_byte_2 (0x33) Read  ######################################################################## -#set $top_agc3_read_names = ', '.join(map(lambda x: str(int(round(1.92*x+94))) + 'dbuvrms=' + str(x), range(0,8))) -##reserved            0x33[3:7]     0 -top_agc3_read         0x33[0:2]     0   $top_agc3_read_names +## reserved            0x33[3:7]     0 +<% top_agc3_read_names = ', '.join(map(lambda x: str(int(round(1.92*x+94))) + 'dbuvrms=' + str(x), range(0,8))) %>\ +top_agc3_read         0x33[0:2]     0   ${top_agc3_read_names}  ########################################################################  ##  IF_AGC_Gain_byte (0x34) Read  ######################################################################## -#set $lpf_gain_names = ', '.join(map(lambda x: str(3*x) + 'db=' + str(x), range(0,4))) -#set $ir_mixer_names = ', '.join(map(lambda x: str(3*x+2) + 'db=' + str(x), range(0,5))) -##reserved            0x34[5:7]     0 -agc5_gain_read        0x34[3:4]     3   $lpf_gain_names -agc4_gain_read        0x34[0:2]     4   $ir_mixer_names +## reserved            0x34[5:7]     0 +<% +    lpf_gain_names = ', '.join(map(lambda x: str(3*x) + 'db=' + str(x), range(0,4))) +    ir_mixer_names = ', '.join(map(lambda x: str(3*x+2) + 'db=' + str(x), range(0,5))) +%>\ +agc5_gain_read        0x34[3:4]     3   ${lpf_gain_names} +agc4_gain_read        0x34[0:2]     4   ${ir_mixer_names}  ########################################################################  ##  Power_byte_1 (0x35) Read  ######################################################################## @@ -399,9 +407,9 @@ rssi                  0x35[0:7]     0  ########################################################################  ##  Power_byte_2 (0x36) Read  ######################################################################## -##reserved            0x36[6:7]     0 +## reserved           0x36[6:7]     0  rssi_av               0x36[5]       0 -##reserved            0x36[4]       0 +## reserved           0x36[4]       0  rssi_cap_reset_en     0x36[3]       1  rssi_cap_val          0x36[2]       1  rssi_ck_speed         0x36[1]       0 @@ -479,39 +487,30 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return boost::uint8_t(reg);  }  void set_reg(boost::uint8_t addr, boost::uint8_t reg){      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        ${reg.get_name()} = ${reg.get_type()}((reg >> ${reg.get_shift()}) & ${reg.get_mask()}); +        % endfor          break; -    #end for +    % endfor      }  }  """ -SPLIT_REGS_HELPER_TMPL="""\ -#for $divname in ['n','f'] -void set_$(divname)_divider(boost::uint32_t $divname){ -    #for $regname in sorted(map(lambda r: r.get_name(), filter(lambda r: r.get_name().find(divname + '_divider') == 0, $regs))) -    #end for -} -#end for -""" -  if __name__ == '__main__':      import common; common.generate(          name='tda18272hnm_regs', diff --git a/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py index 73f7aa3db..9b8e1958f 100644..100755 --- a/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py +++ b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py @@ -53,13 +53,13 @@ BODY_TMPL="""\  boost::uint8_t get_reg(boost::uint8_t addr){      boost::uint8_t reg = 0;      switch(addr){ -    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) -    case $addr: -        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) -        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); -        #end for +    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))): +    case ${addr}: +        % for reg in filter(lambda r: r.get_addr() == addr, regs): +        reg |= (boost::uint8_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()}; +        % endfor          break; -    #end for +    % endfor      }      return boost::uint8_t(reg);  } diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 5920f3d78..9ec8a5c0b 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -129,6 +129,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp  )  # Verbose Debug output for send/recv diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp new file mode 100644 index 000000000..632887e56 --- /dev/null +++ b/host/lib/transport/chdr.cpp @@ -0,0 +1,182 @@ +// +// Copyright 2014 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/chdr.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/exception.hpp> + +//define the endian macros to convert integers +#ifdef BOOST_BIG_ENDIAN +    #define BE_MACRO(x) (x) +    #define LE_MACRO(x) uhd::byteswap(x) +#else +    #define BE_MACRO(x) uhd::byteswap(x) +    #define LE_MACRO(x) (x) +#endif + +using namespace uhd::transport::vrt; + +static const boost::uint32_t HDR_FLAG_TSF = (1 << 29); +static const boost::uint32_t HDR_FLAG_EOB = (1 << 28); +static const boost::uint32_t HDR_FLAG_ERROR = (1 << 28); + +/***************************************************************************/ +/* Packing                                                                 */ +/***************************************************************************/ +/*! Translate the contents of \p if_packet_info into a 32-Bit word and return it. + */ +UHD_INLINE boost::uint32_t _hdr_pack_chdr( +        if_packet_info_t &if_packet_info +) { +    // Set fields in if_packet_info +    if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0); +    if_packet_info.num_packet_words32 = +            if_packet_info.num_header_words32 + +            if_packet_info.num_payload_words32; + +    boost::uint16_t pkt_length = +        if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32); +    boost::uint32_t chdr = 0 +        // 2 Bits: Packet type +        | (if_packet_info.packet_type << 30) +        // 1 Bit: Has time +        | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0) +        // 1 Bit: EOB or Error +        | ((if_packet_info.eob or if_packet_info.error) ? HDR_FLAG_EOB : 0) +        // 12 Bits: Sequence number +        | ((if_packet_info.packet_count & 0xFFF) << 16) +        // 16 Bits: Total packet length +        | pkt_length; +    return chdr; +} + +void chdr::if_hdr_pack_be( +        boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info +) { +    // Write header and update if_packet_info +    packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info)); + +    // Write SID +    packet_buff[1] = BE_MACRO(if_packet_info.sid); + +    // Write time +    if (if_packet_info.has_tsf) { +        packet_buff[2] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32)); +        packet_buff[3] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0)); +    } +} + +void chdr::if_hdr_pack_le( +        boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info +) { +    // Write header and update if_packet_info +    packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info)); + +    // Write SID +    packet_buff[1] = LE_MACRO(if_packet_info.sid); + +    // Write time +    if (if_packet_info.has_tsf) { +        packet_buff[2] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32)); +        packet_buff[3] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0)); +    } +} + + +/***************************************************************************/ +/* Unpacking                                                               */ +/***************************************************************************/ +UHD_INLINE void _hdr_unpack_chdr( +        const boost::uint32_t chdr, +        if_packet_info_t &if_packet_info +) { +    // Set constant members +    if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR; +    if_packet_info.has_cid = false; +    if_packet_info.has_sid = true; +    if_packet_info.has_tsi = false; +    if_packet_info.has_tlr = false; +    if_packet_info.sob = false; + +    // Set configurable members +    if_packet_info.has_tsf = (chdr & HDR_FLAG_TSF) > 0; +    if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3); +    if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA) +                         && ((chdr & HDR_FLAG_EOB) > 0); +    if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP) +                         && ((chdr & HDR_FLAG_ERROR) > 0); +    if_packet_info.packet_count = (chdr >> 16) & 0xFFF; + +    // Set packet length variables +    if (if_packet_info.has_tsf) { +        if_packet_info.num_header_words32 = 4; +    } else { +        if_packet_info.num_header_words32 = 2; +    } +    size_t pkt_size_bytes = (chdr & 0xFFFF); +    size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0); +    // Check lengths match: +    if (pkt_size_word32 < if_packet_info.num_header_words32) { +        throw uhd::value_error("Bad CHDR or invalid packet length"); +    } +    if (if_packet_info.num_packet_words32 < pkt_size_word32) { +        throw uhd::value_error("Bad CHDR or packet fragment"); +    } +    if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32); +    if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32; +} + +void chdr::if_hdr_unpack_be( +        const boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info +) { +    // Read header and update if_packet_info +    boost::uint32_t chdr = BE_MACRO(packet_buff[0]); +    _hdr_unpack_chdr(chdr, if_packet_info); + +    // Read SID +    if_packet_info.sid = BE_MACRO(packet_buff[1]); + +    // Read time (has_tsf was updated earlier) +    if (if_packet_info.has_tsf) { +        if_packet_info.tsf = 0 +            | boost::uint64_t(BE_MACRO(packet_buff[2])) << 32 +            | BE_MACRO(packet_buff[3]); +    } +} + +void chdr::if_hdr_unpack_le( +        const boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info +) { +    // Read header and update if_packet_info +    boost::uint32_t chdr = LE_MACRO(packet_buff[0]); +    _hdr_unpack_chdr(chdr, if_packet_info); + +    // Read SID +    if_packet_info.sid = LE_MACRO(packet_buff[1]); + +    // Read time (has_tsf was updated earlier) +    if (if_packet_info.has_tsf) { +        if_packet_info.tsf = 0 +            | boost::uint64_t(LE_MACRO(packet_buff[2])) << 32 +            | LE_MACRO(packet_buff[3]); +    } +} + diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py index 98f6804ae..6723e3a4b 100644 --- a/host/lib/transport/gen_vrt_if_packet.py +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2013,2015 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,26 +25,25 @@ metatdata into vrt headers and vrt headers into metadata.  The generated code infers jump tables to speed-up the parsing time.  """ -TMPL_TEXT = """ -#import time +TMPL_TEXT = """<% import time %>  /*********************************************************************** - * This file was generated by $file on $time.strftime("%c") + * This file was generated by ${file} on ${time.strftime("%c")}   **********************************************************************/ -\#include <uhd/exception.hpp> -\#include <uhd/transport/vrt_if_packet.hpp> -\#include <uhd/utils/byteswap.hpp> -\#include <boost/detail/endian.hpp> -\#include <vector> +#include <uhd/exception.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/detail/endian.hpp> +#include <vector>  //define the endian macros to convert integers -\#ifdef BOOST_BIG_ENDIAN -    \#define BE_MACRO(x) (x) -    \#define LE_MACRO(x) uhd::byteswap(x) -\#else -    \#define BE_MACRO(x) uhd::byteswap(x) -    \#define LE_MACRO(x) (x) -\#endif +#ifdef BOOST_BIG_ENDIAN +    #define BE_MACRO(x) (x) +    #define LE_MACRO(x) uhd::byteswap(x) +#else +    #define BE_MACRO(x) uhd::byteswap(x) +    #define LE_MACRO(x) (x) +#endif  using namespace uhd;  using namespace uhd::transport; @@ -59,13 +58,13 @@ static pred_table_type get_pred_unpack_table(void)      pred_table_type table(1 << 9, 0); //only 9 bits useful here (20-28)      for (size_t i = 0; i < table.size(); i++){          boost::uint32_t vrt_hdr_word = i << 20; -        if(vrt_hdr_word & $hex(0x1 << 28)) table[i] |= $hex($sid_p); -        if(vrt_hdr_word & $hex(0x1 << 27)) table[i] |= $hex($cid_p); -        if(vrt_hdr_word & $hex(0x3 << 22)) table[i] |= $hex($tsi_p); -        if(vrt_hdr_word & $hex(0x3 << 20)) table[i] |= $hex($tsf_p); -        if(vrt_hdr_word & $hex(0x1 << 26)) table[i] |= $hex($tlr_p); -        if(vrt_hdr_word & $hex(0x1 << 24)) table[i] |= $hex($eob_p); -        if(vrt_hdr_word & $hex(0x1 << 25)) table[i] |= $hex($sob_p); +        if(vrt_hdr_word & ${hex(0x1 << 28)}) table[i] |= ${hex(sid_p)}; +        if(vrt_hdr_word & ${hex(0x1 << 27)}) table[i] |= ${hex(cid_p)}; +        if(vrt_hdr_word & ${hex(0x3 << 22)}) table[i] |= ${hex(tsi_p)}; +        if(vrt_hdr_word & ${hex(0x3 << 20)}) table[i] |= ${hex(tsf_p)}; +        if(vrt_hdr_word & ${hex(0x1 << 26)}) table[i] |= ${hex(tlr_p)}; +        if(vrt_hdr_word & ${hex(0x1 << 24)}) table[i] |= ${hex(eob_p)}; +        if(vrt_hdr_word & ${hex(0x1 << 25)}) table[i] |= ${hex(sob_p)};      }      return table;  } @@ -105,13 +104,12 @@ UHD_INLINE static boost::uint32_t vrt_to_chdr(const boost::uint32_t vrt, const i  }  ######################################################################## -#def gen_code($XE_MACRO, $suffix) +<%def name="gen_code(XE_MACRO, suffix)">  ######################################################################## -  /*********************************************************************** - * interal impl of packing VRT IF header only + * internal impl of packing VRT IF header only   **********************************************************************/ -UHD_INLINE void __if_hdr_pack_$(suffix)( +UHD_INLINE void __if_hdr_pack_${suffix}(      boost::uint32_t *packet_buff,      if_packet_info_t &if_packet_info,      boost::uint32_t &vrt_hdr_word32 @@ -119,72 +117,53 @@ UHD_INLINE void __if_hdr_pack_$(suffix)(      boost::uint32_t vrt_hdr_flags = 0;      pred_type pred = 0; -    if (if_packet_info.has_sid) pred |= $hex($sid_p); -    if (if_packet_info.has_cid) pred |= $hex($cid_p); -    if (if_packet_info.has_tsi) pred |= $hex($tsi_p); -    if (if_packet_info.has_tsf) pred |= $hex($tsf_p); -    if (if_packet_info.has_tlr) pred |= $hex($tlr_p); -    if (if_packet_info.eob)     pred |= $hex($eob_p); -    if (if_packet_info.sob)     pred |= $hex($sob_p); +    if (if_packet_info.has_sid) pred |= ${hex(sid_p)}; +    if (if_packet_info.has_cid) pred |= ${hex(cid_p)}; +    if (if_packet_info.has_tsi) pred |= ${hex(tsi_p)}; +    if (if_packet_info.has_tsf) pred |= ${hex(tsf_p)}; +    if (if_packet_info.has_tlr) pred |= ${hex(tlr_p)}; +    if (if_packet_info.eob)     pred |= ${hex(eob_p)}; +    if (if_packet_info.sob)     pred |= ${hex(sob_p)};      switch(pred){ -    #for $pred in range(2**7) -    case $pred: -        #set $num_header_words = 1 -        #set $flags = 0 +    % for pred in range(2**7): +    case ${pred}:<% num_header_words = 1 %><% flags = 0 %>          ########## Stream ID ########## -        #if $pred & $sid_p -            packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); -            #set $num_header_words += 1 -            #set $flags |= (0x1 << 28); -        #end if +        % if pred & sid_p: +            packet_buff[${num_header_words}] = ${XE_MACRO}(if_packet_info.sid);<% num_header_words += 1 %><% flags |= (0x1 << 28) %> +        % endif          ########## Class ID ########## -        #if $pred & $cid_p -            packet_buff[$num_header_words] = 0; //not implemented -            #set $num_header_words += 1 -            packet_buff[$num_header_words] = 0; //not implemented -            #set $num_header_words += 1 -            #set $flags |= (0x1 << 27); -        #end if +        % if pred & cid_p: +            packet_buff[${num_header_words}] = 0; //not implemented<% num_header_words += 1 %> +            packet_buff[${num_header_words}] = 0; //not implemented<% num_header_words += 1 %><% flags |= (0x1 << 27) %> +        % endif          ########## Integer Time ########## -        #if $pred & $tsi_p -            packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); -            #set $num_header_words += 1 -            #set $flags |= (0x3 << 22); -        #end if +        % if pred & tsi_p: +            packet_buff[${num_header_words}] = ${XE_MACRO}(if_packet_info.tsi);<% num_header_words += 1 %><% flags |= (0x3 << 22) %> +        % endif          ########## Fractional Time ########## -        #if $pred & $tsf_p -            packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 32)); -            #set $num_header_words += 1 -            packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 0)); -            #set $num_header_words += 1 -            #set $flags |= (0x1 << 20); -        #end if +        % if pred & tsf_p: +            packet_buff[${num_header_words}] = ${XE_MACRO}(boost::uint32_t(if_packet_info.tsf >> 32));<% num_header_words += 1 %> +            packet_buff[${num_header_words}] = ${XE_MACRO}(boost::uint32_t(if_packet_info.tsf >> 0));<% num_header_words += 1 %><% flags |= (0x1 << 20) %> +        % endif          ########## Burst Flags ########## -        #if $pred & $eob_p -            #set $flags |= (0x1 << 24); -        #end if -        #if $pred & $sob_p -            #set $flags |= (0x1 << 25); -        #end if +<% if pred & eob_p: flags |= (0x1 << 24) %><% if pred & sob_p: flags |= (0x1 << 25) %>          ########## Trailer ########## -        #if $pred & $tlr_p +        % if pred & tlr_p:              {                  const size_t empty_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - if_packet_info.num_payload_bytes;                  if_packet_info.tlr = (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10);              } -            packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); -            #set $flags |= (0x1 << 26); -            #set $num_trailer_words = 1; -        #else -            #set $num_trailer_words = 0; -        #end if +            packet_buff[${num_header_words}+if_packet_info.num_payload_words32] = ${XE_MACRO}(if_packet_info.tlr);<% flags |= (0x1 << 26) %><% num_trailer_words = 1 %> +        % else: +<% num_trailer_words = 0 %> +        % endif          ########## Variables ########## -            if_packet_info.num_header_words32 = $num_header_words; -            if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; -            vrt_hdr_flags = $hex($flags); +            if_packet_info.num_header_words32 = ${num_header_words}; +            if_packet_info.num_packet_words32 = ${num_header_words + num_trailer_words} + if_packet_info.num_payload_words32; +            vrt_hdr_flags = ${hex(flags)};          break; -    #end for +    % endfor      }      //fill in complete header word @@ -197,9 +176,9 @@ UHD_INLINE void __if_hdr_pack_$(suffix)(  }  /*********************************************************************** - * interal impl of unpacking VRT IF header only + * internal impl of unpacking VRT IF header only   **********************************************************************/ -UHD_INLINE void __if_hdr_unpack_$(suffix)( +UHD_INLINE void __if_hdr_unpack_${suffix}(      const boost::uint32_t *packet_buff,      if_packet_info_t &if_packet_info,      const boost::uint32_t vrt_hdr_word32 @@ -219,86 +198,78 @@ UHD_INLINE void __if_hdr_unpack_$(suffix)(      size_t empty_bytes = 0;      switch(pred){ -    #for $pred in range(2**7) -    case $pred: -        #set $has_time_spec = False -        #set $num_header_words = 1 +    % for pred in range(2**7): +    case ${pred}:<% has_time_spec = False %><% num_header_words = 1 %>          ########## Stream ID ########## -        #if $pred & $sid_p +        % if pred & sid_p:              if_packet_info.has_sid = true; -            if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); -            #set $num_header_words += 1 -        #else +            if_packet_info.sid = ${XE_MACRO}(packet_buff[${num_header_words}]);<% num_header_words += 1 %> +        % else:              if_packet_info.has_sid = false; -        #end if +        % endif          ########## Class ID ########## -        #if $pred & $cid_p +        % if pred & cid_p:              if_packet_info.has_cid = true; -            if_packet_info.cid = 0; //not implemented -            #set $num_header_words += 2 -        #else +            if_packet_info.cid = 0; //not implemented<% num_header_words += 2 %> +        % else:              if_packet_info.has_cid = false; -        #end if +        % endif          ########## Integer Time ########## -        #if $pred & $tsi_p +        % if pred & tsi_p:              if_packet_info.has_tsi = true; -            if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); -            #set $num_header_words += 1 -        #else +            if_packet_info.tsi = ${XE_MACRO}(packet_buff[${num_header_words}]); +<% num_header_words += 1 %> +        % else:              if_packet_info.has_tsi = false; -        #end if +        % endif          ########## Fractional Time ########## -        #if $pred & $tsf_p +        % if pred & tsf_p:              if_packet_info.has_tsf = true; -            if_packet_info.tsf = boost::uint64_t($(XE_MACRO)(packet_buff[$num_header_words])) << 32; -            #set $num_header_words += 1 -            if_packet_info.tsf |= $(XE_MACRO)(packet_buff[$num_header_words]); -            #set $num_header_words += 1 -        #else +            if_packet_info.tsf = boost::uint64_t(${XE_MACRO}(packet_buff[${num_header_words}])) << 32;<% num_header_words += 1 %> +            if_packet_info.tsf |= ${XE_MACRO}(packet_buff[${num_header_words}]);<% num_header_words += 1 %> +        % else:              if_packet_info.has_tsf = false; -        #end if +        % endif          ########## Burst Flags ########## -        #if $pred & $eob_p +        % if pred & eob_p:              if_packet_info.eob = true; -        #else +        % else:              if_packet_info.eob = false; -        #end if -        #if $pred & $sob_p +        % endif +        % if pred & sob_p:              if_packet_info.sob = true; -        #else +        % else:              if_packet_info.sob = false; -        #end if +        % endif          ########## Trailer ########## -        #if $pred & $tlr_p +        % if pred & tlr_p:              if_packet_info.has_tlr = true; -            if_packet_info.tlr = $(XE_MACRO)(packet_buff[packet_words32-1]); -            #set $num_trailer_words = 1; +            if_packet_info.tlr = ${XE_MACRO}(packet_buff[packet_words32-1]);<% num_trailer_words = 1 %>              {                  const int indicators = (if_packet_info.tlr >> 20) & (if_packet_info.tlr >> 8);                  if ((indicators & (1 << 0)) != 0) if_packet_info.eob = true;                  if ((indicators & (1 << 1)) != 0) if_packet_info.sob = true;                  empty_bytes = occ_table[(indicators >> 2) & 0x3];              } -        #else -            if_packet_info.has_tlr = false; -            #set $num_trailer_words = 0; -        #end if +        % else: +            if_packet_info.has_tlr = false;<% num_trailer_words = 0 %> +        % endif          ########## Variables ##########              //another failure case -            if (packet_words32 < $($num_header_words + $num_trailer_words)) +            if (packet_words32 < ${num_header_words + num_trailer_words})                  throw uhd::value_error("bad vrt header or invalid packet length"); -            if_packet_info.num_header_words32 = $num_header_words; -            if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); +            if_packet_info.num_header_words32 = ${num_header_words}; +            if_packet_info.num_payload_words32 = packet_words32 - ${num_header_words + num_trailer_words};              if_packet_info.num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - empty_bytes;          break; -    #end for +    % endfor      }  }  /***********************************************************************   * link layer + VRT IF packing   **********************************************************************/ -void vrt::if_hdr_pack_$(suffix)( +void vrt::if_hdr_pack_${suffix}(      boost::uint32_t *packet_buff,      if_packet_info_t &if_packet_info  ){ @@ -306,29 +277,29 @@ void vrt::if_hdr_pack_$(suffix)(      switch (if_packet_info.link_type)      {      case if_packet_info_t::LINK_TYPE_NONE: -        __if_hdr_pack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); -        packet_buff[0] = $(XE_MACRO)(vrt_hdr_word32); +        __if_hdr_pack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32); +        packet_buff[0] = ${XE_MACRO}(vrt_hdr_word32);          break;      case if_packet_info_t::LINK_TYPE_CHDR:      { -        __if_hdr_pack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); +        __if_hdr_pack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32);          const boost::uint32_t chdr = vrt_to_chdr(vrt_hdr_word32, if_packet_info); -        packet_buff[0] = $(XE_MACRO)(chdr); +        packet_buff[0] = ${XE_MACRO}(chdr);          break;      }      case if_packet_info_t::LINK_TYPE_VRLP: -        __if_hdr_pack_$(suffix)(packet_buff+2, if_packet_info, vrt_hdr_word32); +        __if_hdr_pack_${suffix}(packet_buff+2, if_packet_info, vrt_hdr_word32);          if_packet_info.num_header_words32 += 2;          if_packet_info.num_packet_words32 += 3; -        packet_buff[0] = $(XE_MACRO)(VRLP); -        packet_buff[1] = $(XE_MACRO)(boost::uint32_t( +        packet_buff[0] = ${XE_MACRO}(VRLP); +        packet_buff[1] = ${XE_MACRO}(boost::uint32_t(              (if_packet_info.num_packet_words32 & 0xfffff) |              ((if_packet_info.packet_count & 0xfff) << 20)          )); -        packet_buff[2] = $(XE_MACRO)(vrt_hdr_word32); -        packet_buff[if_packet_info.num_packet_words32-1] = $(XE_MACRO)(VEND); +        packet_buff[2] = ${XE_MACRO}(vrt_hdr_word32); +        packet_buff[if_packet_info.num_packet_words32-1] = ${XE_MACRO}(VEND);          break;      }  } @@ -336,7 +307,7 @@ void vrt::if_hdr_pack_$(suffix)(  /***********************************************************************   * link layer + VRT IF unpacking   **********************************************************************/ -void vrt::if_hdr_unpack_$(suffix)( +void vrt::if_hdr_unpack_${suffix}(      const boost::uint32_t *packet_buff,      if_packet_info_t &if_packet_info  ){ @@ -344,16 +315,16 @@ void vrt::if_hdr_unpack_$(suffix)(      switch (if_packet_info.link_type)      {      case if_packet_info_t::LINK_TYPE_NONE: -        vrt_hdr_word32 = $(XE_MACRO)(packet_buff[0]); -        __if_hdr_unpack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); +        vrt_hdr_word32 = ${XE_MACRO}(packet_buff[0]); +        __if_hdr_unpack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32);          break;      case if_packet_info_t::LINK_TYPE_CHDR:      { -        const boost::uint32_t chdr = $(XE_MACRO)(packet_buff[0]); +        const boost::uint32_t chdr = ${XE_MACRO}(packet_buff[0]);          vrt_hdr_word32 = chdr_to_vrt(chdr, if_packet_info);          size_t packet_count = if_packet_info.packet_count; -        __if_hdr_unpack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); +        __if_hdr_unpack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32);          if_packet_info.num_payload_bytes -= (~chdr + 1) & 0x3;          if_packet_info.packet_count = packet_count;          break; @@ -361,12 +332,12 @@ void vrt::if_hdr_unpack_$(suffix)(      case if_packet_info_t::LINK_TYPE_VRLP:      { -        if ($(XE_MACRO)(packet_buff[0]) != VRLP) throw uhd::value_error("bad vrl header VRLP"); -        const boost::uint32_t vrl_hdr = $(XE_MACRO)(packet_buff[1]); -        vrt_hdr_word32 = $(XE_MACRO)(packet_buff[2]); +        if (${XE_MACRO}(packet_buff[0]) != VRLP) throw uhd::value_error("bad vrl header VRLP"); +        const boost::uint32_t vrl_hdr = ${XE_MACRO}(packet_buff[1]); +        vrt_hdr_word32 = ${XE_MACRO}(packet_buff[2]);          if (if_packet_info.num_packet_words32 < (vrl_hdr & 0xfffff)) throw uhd::value_error("bad vrl header or packet fragment"); -        if ($(XE_MACRO)(packet_buff[(vrl_hdr & 0xfffff)-1]) != VEND) throw uhd::value_error("bad vrl trailer VEND"); -        __if_hdr_unpack_$(suffix)(packet_buff+2, if_packet_info, vrt_hdr_word32); +        if (${XE_MACRO}(packet_buff[(vrl_hdr & 0xfffff)-1]) != VEND) throw uhd::value_error("bad vrl trailer VEND"); +        __if_hdr_unpack_${suffix}(packet_buff+2, if_packet_info, vrt_hdr_word32);          if_packet_info.num_header_words32 += 2; //add vrl header          if_packet_info.packet_count = (vrl_hdr >> 20) & 0xfff;          break; @@ -375,16 +346,16 @@ void vrt::if_hdr_unpack_$(suffix)(  }  ######################################################################## -#end def +</%def>  ######################################################################## -$gen_code("BE_MACRO", "be") -$gen_code("LE_MACRO", "le") +${gen_code("BE_MACRO", "be")} +${gen_code("LE_MACRO", "le")}  """  def parse_tmpl(_tmpl_text, **kwargs): -    from Cheetah.Template import Template -    return str(Template(_tmpl_text, kwargs)) +    from mako.template import Template +    return Template(_tmpl_text).render(**kwargs)  if __name__ == '__main__':      import sys diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index ae33cc036..0baf8dc76 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -345,15 +345,21 @@ libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){  std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(      boost::uint16_t vid, boost::uint16_t pid  ){ -    std::vector<usb_device_handle::sptr> handles; +    return usb_device_handle::get_device_list(std::vector<usb_device_handle::vid_pid_pair_t>(1,usb_device_handle::vid_pid_pair_t(vid,pid))); +} +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list) +{ +    std::vector<usb_device_handle::sptr> handles;      libusb::device_list::sptr dev_list = libusb::device_list::make(); -    for (size_t i = 0; i < dev_list->size(); i++){ -        usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); -        if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){ -            handles.push_back(handle); -        } +    for(size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter) +    { +       for (size_t i = 0; i < dev_list->size(); i++){ +           usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); +           if (handle->get_vendor_id() == vid_pid_pair_list[iter].first and handle->get_product_id() == vid_pid_pair_list[iter].second){ +               handles.push_back(handle); +           } +       }      } -      return handles;  } diff --git a/host/lib/transport/nirio/lvbitx/process-lvbitx.py b/host/lib/transport/nirio/lvbitx/process-lvbitx.py index ab9625608..7887c3997 100755 --- a/host/lib/transport/nirio/lvbitx/process-lvbitx.py +++ b/host/lib/transport/nirio/lvbitx/process-lvbitx.py @@ -1,6 +1,6 @@  #!/usr/bin/python  # -# Copyright 2013-2014 Ettus Research LLC +# Copyright 2013-2015 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 @@ parser.add_option("--output-src-path", type="string", dest="output_src_path", he  # Args  if (len(args) < 1): -    print 'ERROR: Please specify the input LVBITX file name' +    print('ERROR: Please specify the input LVBITX file name')      sys.exit(1)  lvbitx_filename = args[0] @@ -44,16 +44,16 @@ autogen_src_path = os.path.abspath(options.output_src_path) if (options.output_s  class_name = os.path.splitext(os.path.basename(input_filename))[0]  if (not os.path.isfile(input_filename)): -    print 'ERROR: FPGA File ' + input_filename + ' could not be accessed or is not a file.' +    print('ERROR: FPGA File ' + input_filename + ' could not be accessed or is not a file.')      sys.exit(1)  if (options.merge_bin is not None and not os.path.isfile(os.path.abspath(options.merge_bin))): -    print 'ERROR: FPGA Bin File ' + options.merge_bin + ' could not be accessed or is not a file.' +    print('ERROR: FPGA Bin File ' + options.merge_bin + ' could not be accessed or is not a file.')      sys.exit(1)  if (not os.path.exists(autogen_src_path)): -    print 'ERROR: Output path ' + autogen_src_path + ' could not be accessed.' +    print('ERROR: Output path ' + autogen_src_path + ' could not be accessed.')      sys.exit(1)  if (options.output_lvbitx_path is not None and input_filename == os.path.join(autogen_src_path, class_name + '.lvbitx')): -    print 'ERROR: Input and output LVBITX files were the same. Choose a difference input file or output path.' +    print('ERROR: Input and output LVBITX files were the same. Choose a difference input file or output path.')      sys.exit(1)  # Get XML Tree Node @@ -122,7 +122,7 @@ def map_SubType_to_ScalarType(SubType):      elif SubType == 'U64':          ScalarType = 'RIO_SCALAR_TYPE_UQ'      else: -        print 'ERROR: No corresponding nirio_scalar_type_t value for SubType ' + SubType + ' .' +        print('ERROR: No corresponding nirio_scalar_type_t value for SubType ' + SubType + ' .')          sys.exit(1)      return ScalarType; @@ -187,7 +187,7 @@ codegen_transform['lvbitx_signature'] = str.upper(root.find('SignatureRegister')  # Write BIN file  bitstream = base64.b64decode(root.find('Bitstream').text)  if (options.output_lvbitx_path is not None and hashlib.md5(bitstream).hexdigest() != root.find('BitstreamMD5').text): -    print 'ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.' +    print('ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.')      sys.exit(1)  if (options.output_bin):      fpga_bin_file = open(os.path.join(options.output_lvbitx_path, class_name + '.bin'), 'w') diff --git a/host/lib/transport/nirio/rpc/rpc_client.cpp b/host/lib/transport/nirio/rpc/rpc_client.cpp index cf8e9c1a9..48f47cfae 100644 --- a/host/lib/transport/nirio/rpc/rpc_client.cpp +++ b/host/lib/transport/nirio/rpc/rpc_client.cpp @@ -52,7 +52,7 @@ rpc_client::rpc_client (          //- address_configured: Only return addresses if a non-loopback address is configured for the system.          //- numeric_host: No name resolution should be attempted for host          //- numeric_service: No name resolution should be attempted for service -        tcp::resolver::query::flags query_flags; +        tcp::resolver::query::flags query_flags = tcp::resolver::query::passive;          tcp::resolver::query query(tcp::v4(), server, port, query_flags);          tcp::resolver::iterator iterator = resolver.resolve(query); diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 5c84327a4..c3c2b8e97 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -147,7 +147,7 @@ public:       */      void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff, const bool flush = false){          if (flush){ -            while (get_buff(0.0)); +            while (get_buff(0.0)) {};          }          _props.at(xport_chan).get_buff = get_buff;      } diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index f19043c1e..5e97628f0 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2011-2013 Ettus Research LLC +# Copyright 2011-2013,2015 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,8 +86,11 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/sid.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/filters.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/byte_vector.cpp  ) diff --git a/host/lib/types/byte_vector.cpp b/host/lib/types/byte_vector.cpp new file mode 100644 index 000000000..071cdb8cb --- /dev/null +++ b/host/lib/types/byte_vector.cpp @@ -0,0 +1,42 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/foreach.hpp> + +#include <uhd/types/byte_vector.hpp> + +namespace uhd{ + +std::string bytes_to_string(const byte_vector_t &bytes){ +    std::string out; +    BOOST_FOREACH(boost::uint8_t byte, bytes){ +        if (byte < 32 or byte > 127) return out; +        out += byte; +    } +    return out; +} + +byte_vector_t string_to_bytes(const std::string &str, size_t max_length){ +    byte_vector_t bytes; +    for (size_t i = 0; i < std::min(str.size(), max_length); i++){ +        bytes.push_back(str[i]); +    } +    if (bytes.size() < max_length - 1) bytes.push_back('\0'); +    return bytes; +} + +} /* namespace uhd */ diff --git a/host/lib/types/filters.cpp b/host/lib/types/filters.cpp new file mode 100644 index 000000000..4ee06491f --- /dev/null +++ b/host/lib/types/filters.cpp @@ -0,0 +1,74 @@ +// +// Copyright 2015 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/filters.hpp> + +using namespace uhd; + +std::ostream& uhd::operator<<(std::ostream& os, filter_info_base& f) +{ +    return os << f.to_pp_string(); +} + +std::string filter_info_base::to_pp_string() +{ +    std::ostringstream os; +    os << "[filter_info_base]" << std::endl; +    switch(_type){ +        case ANALOG_LOW_PASS: +            os << "type: " << "Analog Low-pass" << std::endl; +            break; +        case ANALOG_BAND_PASS: +            os << "type: " << "Analog Band-pass" << std::endl; +            break; +        case DIGITAL_I16: +            os << "type: " << "Digital (i16)" << std::endl; +            break; +        case DIGITAL_FIR_I16: +            os << "type: " << "Digital FIR (i16)" << std::endl; +            break; +        default: +            os << "type: " << "Unknown type!" << std::endl; +            break; +        } + +    os << "bypass enable: " << _bypass << std::endl +        <<"position index: " << _position_index << std::endl; + +    std::string str =  os.str(); +    return str; +} + +std::string analog_filter_base::to_pp_string() +{ +    std::ostringstream os; +    os << filter_info_base::to_pp_string() << +        "\t[analog_filter_base]" << std::endl << +        "\tdesc: " << _analog_type << std::endl; +    return std::string(os.str()); + +} + +std::string analog_filter_lp::to_pp_string() +{ +    std::ostringstream os; +    os << analog_filter_base::to_pp_string() << +        "\t\t[analog_filter_lp]" << std::endl << +        "\t\tcutoff: " << _cutoff << std::endl << +        "\t\trolloff: " << _rolloff << std::endl; +    return std::string(os.str()); +} diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp new file mode 100644 index 000000000..2fc3781cf --- /dev/null +++ b/host/lib/types/sid.cpp @@ -0,0 +1,153 @@ +// +// Copyright 2014 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/format.hpp> +#include <boost/regex.hpp> +#include <boost/lexical_cast.hpp> +#include <uhd/exception.hpp> +#include <uhd/types/sid.hpp> +#include <uhd/utils/cast.hpp> + +using namespace uhd; + +sid_t::sid_t() +    : _sid(0x0000), _set(false) +{ +} + +sid_t::sid_t(boost::uint32_t sid) +    : _sid(sid), _set(true) +{ +} + +sid_t::sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep) +    :  _sid(0x0000), _set(true) +{ +    set_src_addr(src_addr); +    set_src_endpoint(src_ep); +    set_dst_addr(dst_addr); +    set_dst_endpoint(dst_ep); +} + +sid_t::sid_t(const std::string &sid_str) +    : _sid(0x0000), _set(false) +{ +    set_from_str(sid_str); +} + +std::string sid_t::to_pp_string() const +{ +    if (not _set) { +        return "x.x>x.x"; +    } +    return str(boost::format("%d.%d>%d.%d") +        % get_src_addr() +        % get_src_endpoint() +        % get_dst_addr() +        % get_dst_endpoint() +    ); +} + +std::string sid_t::to_pp_string_hex() const +{ +    if (not _set) { +        return "xx:xx>xx:xx"; +    } +    return str(boost::format("%02x:%02x>%02x:%02x") +        % get_src_addr() +        % get_src_endpoint() +        % get_dst_addr() +        % get_dst_endpoint() +    ); +} + + +void sid_t::set_sid(boost::uint32_t new_sid) +{ +    _set = true; +    _sid = new_sid; +} + +void sid_t::set_from_str(const std::string &sid_str) +{ +    const std::string dec_regex = "(\\d{1,3})\\.(\\d{1,3})[.:/><](\\d{1,3})\\.(\\d{1,3})"; +    const std::string hex_regex = "([[:xdigit:]]{2}):([[:xdigit:]]{2})[.:/><]([[:xdigit:]]{2}):([[:xdigit:]]{2})"; + +    boost::cmatch matches; +    if (boost::regex_match(sid_str.c_str(), matches, boost::regex(dec_regex))) { +        set_src_addr(boost::lexical_cast<size_t>(matches[1])); +        set_src_endpoint(boost::lexical_cast<size_t>(matches[2])); +        set_dst_addr(boost::lexical_cast<size_t>(matches[3])); +        set_dst_endpoint(boost::lexical_cast<size_t>(matches[4])); +        return; +    } + +    if (boost::regex_match(sid_str.c_str(), matches, boost::regex(hex_regex))) { +        set_src_addr(uhd::cast::hexstr_cast<size_t>(matches[1])); +        set_src_endpoint(uhd::cast::hexstr_cast<size_t>(matches[2])); +        set_dst_addr(uhd::cast::hexstr_cast<size_t>(matches[3])); +        set_dst_endpoint(uhd::cast::hexstr_cast<size_t>(matches[4])); +        return; +    } + +    throw uhd::value_error(str(boost::format("Invalid SID representation: %s") % sid_str)); +} + +void sid_t::set_src(boost::uint32_t new_addr) { +    set_sid((_sid & 0x0000FFFF) | ((new_addr & 0xFFFF) << 16)); +} + +void sid_t::set_dst(boost::uint32_t new_addr) { +    set_sid((_sid & 0xFFFF0000) | (new_addr & 0xFFFF)); +} + +void sid_t::set_src_addr(boost::uint32_t new_addr) { +    set_sid((_sid & 0x00FFFFFF) | ((new_addr & 0xFF) << 24)); +} + +void sid_t::set_src_endpoint(boost::uint32_t new_addr) { +    set_sid((_sid & 0xFF00FFFF) | ((new_addr & 0xFF) << 16)); +} + +void sid_t::set_dst_addr(boost::uint32_t new_addr) { +    set_sid((_sid & 0xFFFF00FF) | ((new_addr & 0xFF) << 8)); +} + +void sid_t::set_dst_endpoint(boost::uint32_t new_addr) { +    set_sid((_sid & 0xFFFFFF00) | ((new_addr & 0xFF) << 0)); +} + +void sid_t::set_dst_xbarport(boost::uint32_t new_xbarport) +{ +    set_sid((_sid & 0xFFFFFF0F) | ((new_xbarport & 0xF) << 4)); +} + +void sid_t::set_dst_blockport(boost::uint32_t new_blockport) +{ +    set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0)); +} + +sid_t sid_t::reversed() +{ +    return sid_t((get_dst() << 16) | get_src()); +} + +void sid_t::reverse() +{ +    set_sid((get_dst() << 16) | get_src()); +} + diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 0409adf30..7c672fd46 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2012-2014 Ettus Research LLC +// Copyright 2012-2015 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 @@ -104,14 +104,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)          if (hint_i.has_key("addr") || hint_i.has_key("resource")) return b200_addrs;      } -    boost::uint16_t vid, pid; +    size_t found = 0; +    std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//vid pid pair search list for devices.      if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") { -        vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")); -        pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid")); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")), +                                                                    uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"))));      } else { -        vid = B200_VENDOR_ID; -        pid = B200_PRODUCT_ID; +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));      }      // Important note: @@ -121,8 +123,9 @@ static device_addrs_t b200_find(const device_addr_t &hint)      // This requirement is a courtesy of libusb1.0 on windows.      //find the usrps and load firmware -    size_t found = 0; -    BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { +    std::vector<usb_device_handle::sptr> uhd_usb_device_vector = usb_device_handle::get_device_list(vid_pid_pair_list); + +    BOOST_FOREACH(usb_device_handle::sptr handle, uhd_usb_device_vector) {          //extract the firmware path for the b200          std::string b200_fw_image;          try{ @@ -153,7 +156,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)      //search for the device until found or timeout      while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0)      { -        BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) +        BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid_pid_pair_list))          {              usb_control::sptr control;              try{control = usb_control::make(handle, 0);} @@ -213,13 +216,50 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :      //try to match the given device address with something on the USB bus      boost::uint16_t vid = B200_VENDOR_ID;      boost::uint16_t pid = B200_PRODUCT_ID; +    bool specified_vid = false; +    bool specified_pid = false; +      if (device_addr.has_key("vid")) +    {          vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid")); +        specified_vid = true; +    } +      if (device_addr.has_key("pid")) +    {          pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid")); +        specified_pid = true; +    } + +    std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//search list for devices. + +    // Search only for specified VID and PID if both specified +    if (specified_vid && specified_pid) +    { +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,pid)); +    } +    // Search for all supported PIDs limited to specified VID if only VID specified +    else if (specified_vid) +    { +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID)); +    } +    // Search for all supported VIDs limited to specified PID if only PID specified +    else if (specified_pid) +    { +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,pid)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,pid)); +    } +    // Search for all supported devices if neither VID nor PID specified +    else +    { +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID)); +    } -    std::vector<usb_device_handle::sptr> device_list = -        usb_device_handle::get_device_list(vid, pid); +    std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list);      //locate the matching handle in the device list      usb_device_handle::sptr handle; @@ -447,6 +487,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :          .publish(boost::bind(&b200_impl::get_tick_rate, this))          .subscribe(boost::bind(&b200_impl::update_tick_rate, this, _1));      _tree->create<time_spec_t>(mb_path / "time" / "cmd"); +    _tree->create<bool>(mb_path / "auto_tick_rate").set(false);      ////////////////////////////////////////////////////////////////////      // and do the misc mboard sensors @@ -512,6 +553,19 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :      _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources);      //////////////////////////////////////////////////////////////////// +    // front panel gpio +    //////////////////////////////////////////////////////////////////// +    _radio_perifs[0].fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); +    BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) +    { +            _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second) +            .set(0) +            .subscribe(boost::bind(&b200_impl::set_fp_gpio, this, _radio_perifs[0].fp_gpio, attr.first, _1)); +    } +    _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK") +        .publish(boost::bind(&b200_impl::get_fp_gpio, this, _radio_perifs[0].fp_gpio)); + +    ////////////////////////////////////////////////////////////////////      // dboard eeproms but not really      ////////////////////////////////////////////////////////////////////      dboard_eeprom_t db_eeprom; @@ -549,6 +603,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :          _radio_perifs[i].ddc->set_host_rate(default_tick_rate / B200_DEFAULT_DECIM);          _radio_perifs[i].duc->set_host_rate(default_tick_rate / B200_DEFAULT_INTERP);      } +    // We can automatically choose a master clock rate, but not if the user specifies one +    _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate")); +    if (not device_addr.has_key("master_clock_rate")) { +        UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl; +    }      //GPS installed: use external ref, time, and init time spec      if (_gps and _gps->gps_detected()) @@ -613,7 +672,7 @@ void b200_impl::setup_radio(const size_t dspno)          .publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc));      _tree->create<double>(rx_dsp_path / "rate" / "value")          .set(0.0) // We can only load a sensible value after the tick rate was set -        .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1)) +        .coerce(boost::bind(&b200_impl::coerce_rx_samp_rate, this, perif.ddc, dspno, _1))          .subscribe(boost::bind(&b200_impl::update_rx_samp_rate, this, dspno, _1))      ;      _tree->create<double>(rx_dsp_path / "freq" / "value") @@ -638,7 +697,7 @@ void b200_impl::setup_radio(const size_t dspno)          .publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc));      _tree->create<double>(tx_dsp_path / "rate" / "value")          .set(0.0) // We can only load a sensible value after the tick rate was set -        .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1)) +        .coerce(boost::bind(&b200_impl::coerce_tx_samp_rate, this, perif.duc, dspno, _1))          .subscribe(boost::bind(&b200_impl::update_tx_samp_rate, this, dspno, _1))      ;      _tree->create<double>(tx_dsp_path / "freq" / "value") @@ -682,7 +741,7 @@ void b200_impl::setup_radio(const size_t dspno)          _tree->create<bool>(rf_fe_path / "use_lo_offset").set(false);          _tree->create<double>(rf_fe_path / "bandwidth" / "value")              .coerce(boost::bind(&ad9361_ctrl::set_bw_filter, _codec_ctrl, key, _1)) -            .set(40e6); +            .set(56e6);          _tree->create<meta_range_t>(rf_fe_path / "bandwidth" / "range")              .publish(boost::bind(&ad9361_ctrl::get_bw_filter_range, key));          _tree->create<double>(rf_fe_path / "freq" / "value") @@ -692,8 +751,29 @@ void b200_impl::setup_radio(const size_t dspno)              .set(B200_DEFAULT_FREQ);          _tree->create<meta_range_t>(rf_fe_path / "freq" / "range")              .publish(boost::bind(&ad9361_ctrl::get_rf_freq_range)); +        _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp") +                .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));          //setup RX related stuff +        if(direction) +        { +            _tree->create<bool>(rf_fe_path / "dc_offset" / "enable" ) +                .subscribe(boost::bind(&ad9361_ctrl::set_dc_offset_auto, _codec_ctrl, key, _1)).set(true); + +            _tree->create<bool>(rf_fe_path / "iq_balance" / "enable" ) +                .subscribe(boost::bind(&ad9361_ctrl::set_iq_balance_auto, _codec_ctrl, key, _1)).set(true); +        } + +        //add all frontend filters +        std::vector<std::string> filter_names = _codec_ctrl->get_filter_names(key); +        for(size_t i = 0;i < filter_names.size(); i++) +        { +            _tree->create<filter_info_base::sptr>(rf_fe_path / "filters" / filter_names[i] / "value" ) +                .publish(boost::bind(&ad9361_ctrl::get_filter, _codec_ctrl, key, filter_names[i])) +                .subscribe(boost::bind(&ad9361_ctrl::set_filter, _codec_ctrl, key, filter_names[i], _1)); +        } + +        //setup antenna stuff          if (key[0] == 'R')          {              static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2"); @@ -703,6 +783,16 @@ void b200_impl::setup_radio(const size_t dspno)                  .set("RX2");              _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "rssi")                  .publish(boost::bind(&ad9361_ctrl::get_rssi, _codec_ctrl, key)); + +            //AGC setup +            const std::list<std::string> mode_strings = boost::assign::list_of("slow")("fast"); +            _tree->create<bool>(rf_fe_path / "gain" / "agc" / "enable") +                .subscribe(boost::bind((&ad9361_ctrl::set_agc), _codec_ctrl, key, _1)) +                .set(false); +            _tree->create<std::string>(rf_fe_path / "gain" / "agc" / "mode" / "value") +                .subscribe(boost::bind((&ad9361_ctrl::set_agc_mode), _codec_ctrl, key, _1)).set(mode_strings.front()); +            _tree->create<std::list<std::string> >(rf_fe_path / "gain" / "agc" / "mode" / "options") +                            .set(mode_strings);          }          if (key[0] == 'T')          { @@ -760,7 +850,7 @@ void b200_impl::codec_loopback_self_test(wb_iface::sptr iface)  /***********************************************************************   * Sample and tick rate comprehension below   **********************************************************************/ -void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction /*= NULL*/) +void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction /*= ""*/)  {      const size_t max_chans = 2;      if (chan_count > max_chans) @@ -768,7 +858,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co          throw uhd::value_error(boost::str(              boost::format("cannot not setup %d %s channels (maximum is %d)")                  % chan_count -                % (direction ? direction : "data") +                % (direction.empty() ? "data" : direction)                  % max_chans          ));      } @@ -782,20 +872,26 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co                      % (tick_rate/1e6)                      % (max_tick_rate/1e6)                      % chan_count -                    % (direction ? direction : "data") +                    % (direction.empty() ? "data" : direction)              ));          }      }  } -double b200_impl::set_tick_rate(const double rate) +double b200_impl::set_tick_rate(const double new_tick_rate)  { -    UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz\n") % (rate/1e6)); - -    check_tick_rate_with_current_streamers(rate);   // Defined in b200_io_impl.cpp +    UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz... ") % (new_tick_rate/1e6)) << std::flush; +    check_tick_rate_with_current_streamers(new_tick_rate);   // Defined in b200_io_impl.cpp + +    // Make sure the clock rate is actually changed before doing +    // the full Monty of setting regs and loopback tests etc. +    if (std::abs(new_tick_rate - _tick_rate) < 1.0) { +        UHD_MSG(status) << "OK" << std::endl; +        return _tick_rate; +    } -    _tick_rate = _codec_ctrl->set_clock_rate(rate); -    UHD_MSG(status) << (boost::format("Actually got clock rate %.6f MHz\n") % (_tick_rate/1e6)); +    _tick_rate = _codec_ctrl->set_clock_rate(new_tick_rate); +    UHD_MSG(status) << std::endl << (boost::format("Actually got clock rate %.6f MHz.") % (_tick_rate/1e6)) << std::endl;      //reset after clock rate change      this->reset_codec_dcm(); @@ -856,6 +952,26 @@ void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom)  } +boost::uint32_t b200_impl::get_fp_gpio(gpio_core_200::sptr gpio) +{ +    return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); +} + +void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value) +{ +    switch (attr) +    { +    case GPIO_CTRL:   return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); +    case GPIO_DDR:    return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); +    case GPIO_OUT:    return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); +    case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); +    case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); +    case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); +    case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); +    default:        UHD_THROW_INVALID_CODE_PATH(); +    } +} +  /***********************************************************************   * Reference time and clock   **********************************************************************/ diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 65796d1a4..11c3da0d9 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2012-2013 Ettus Research LLC +// Copyright 2012-2015 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 @@ -45,9 +45,9 @@  #include <uhd/transport/bounded_buffer.hpp>  #include <boost/weak_ptr.hpp>  #include "recv_packet_demuxer_3000.hpp" -static const boost::uint8_t  B200_FW_COMPAT_NUM_MAJOR = 7; +static const boost::uint8_t  B200_FW_COMPAT_NUM_MAJOR = 8;  static const boost::uint8_t  B200_FW_COMPAT_NUM_MINOR = 0; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 8; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 9;  static const double          B200_BUS_CLOCK_RATE = 100e6;  static const double          B200_DEFAULT_TICK_RATE = 32e6;  static const double          B200_DEFAULT_FREQ = 100e6; // Hz @@ -98,7 +98,13 @@ public:      uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args);      uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);      bool recv_async_msg(uhd::async_metadata_t &, double); -    void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL); + +    //! Check that the combination of stream args and tick rate are valid. +    // +    // Basically figures out the arguments for enforce_tick_rate_limits() +    // and calls said method. If arguments are invalid, throws a +    // uhd::value_error. +    void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");  private:      b200_type_t _b200_type; @@ -154,6 +160,7 @@ private:      {          radio_ctrl_core_3000::sptr ctrl;          gpio_core_200_32wo::sptr atr; +        gpio_core_200::sptr fp_gpio;          time_core_3000::sptr time64;          rx_vita_core_3000::sptr framer;          rx_dsp_core_3000::sptr ddc; @@ -200,14 +207,63 @@ private:      void update_enables(void);      void update_atrs(void); +    boost::uint32_t get_fp_gpio(gpio_core_200::sptr); +    void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t); +      double _tick_rate;      double get_tick_rate(void){return _tick_rate;}      double set_tick_rate(const double rate); + +    /*! \brief Choose a tick rate (master clock rate) that works well for the given sampling rate. +     * +     * This function will try and choose a master clock rate automatically. +     * See the function definition for details on the algorithm. +     * +     * The chosen tick rate is the largest multiple of two that is smaler +     * than the max tick rate. +     * The base rate is either given explicitly, or is the lcm() of the tx +     * and rx sampling rates. In that case, it reads the rates directly +     * from the property tree. It also tries to guess the number of channels +     * (for the max possible tick rate) by checking the available streamers. +     * This value, too, can explicitly be given. +     * +     * \param rate If this is given, it will be used as a minimum rate, or +     *             argument to lcm(). +     * \param tree_dsp_path The sampling rate from this property tree path +     *                      will be ignored. +     * \param num_chans If given, specifies the number of channels. +     */ +    void set_auto_tick_rate( +            const double rate=0, +            const uhd::fs_path &tree_dsp_path="", +            size_t num_chans=0 +    ); +      void update_tick_rate(const double); -    void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL); + +    /*! Check if \p tick_rate works with \p chan_count channels. +     * +     * Throws a uhd::value_error if not. +     */ +    void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string  &direction = "");      void check_tick_rate_with_current_streamers(double rate); +    /*! Return the max number of channels on active rx_streamer or tx_streamer objects associated with this device. +     * +     * \param direction Set to "TX" to only check tx_streamers, "RX" to only check +     *                  rx_streamers. Any other value will check if \e any active +     *                  streamers are available. +     * \return Return the number of tx streamers (direction=="TX"), the number of rx +     *         streamers (direction=="RX") or the total number of streamers. +     */ +    size_t max_chan_count(const std::string &direction=""); + +    //! Coercer, attached to the "rate/value" property on the rx dsps. +    double coerce_rx_samp_rate(rx_dsp_core_3000::sptr, size_t, const double);      void update_rx_samp_rate(const size_t, const double); + +    //! Coercer, attached to the "rate/value" property on the tx dsps. +    double coerce_tx_samp_rate(tx_dsp_core_3000::sptr, size_t, const double);      void update_tx_samp_rate(const size_t, const double);  }; diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 1e11e7ff6..c4e04f70a 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2012-2013 Ettus Research LLC +// Copyright 2012-2014 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,10 @@  #include "../../transport/super_recv_packet_handler.hpp"  #include "../../transport/super_send_packet_handler.hpp"  #include "async_packet_handler.hpp" +#include <uhd/utils/math.hpp>  #include <boost/bind.hpp>  #include <boost/make_shared.hpp> +#include <boost/math/common_factor.hpp>  #include <set>  using namespace uhd; @@ -34,30 +36,32 @@ using namespace uhd::transport;   **********************************************************************/  void b200_impl::check_tick_rate_with_current_streamers(double rate)  { -    size_t max_tx_chan_count = 0, max_rx_chan_count = 0; +    // Defined in b200_impl.cpp +    enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX"); +    enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX"); +} + +// direction can either be "TX", "RX", or empty (default) +size_t b200_impl::max_chan_count(const std::string &direction /* = "" */) +{ +    size_t max_count = 0;      BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)      { -        { +        if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) {              boost::shared_ptr<sph::recv_packet_streamer> rx_streamer =                  boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock()); -            if (rx_streamer) -                max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels()); +            max_count = std::max(max_count, rx_streamer->get_num_channels());          } - -        { +        if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) {              boost::shared_ptr<sph::send_packet_streamer> tx_streamer =                  boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); -            if (tx_streamer) -                max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels()); +            max_count = std::max(max_count, tx_streamer->get_num_channels());          }      } - -    // Defined in b200_impl.cpp -    enforce_tick_rate_limits(max_rx_chan_count, rate, "RX"); -    enforce_tick_rate_limits(max_tx_chan_count, rate, "TX"); +    return max_count;  } -void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/) +void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/)  {      std::set<size_t> chans_set;      for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) @@ -69,26 +73,145 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_      enforce_tick_rate_limits(chans_set.size(), tick_rate, direction);   // Defined in b200_impl.cpp  } -void b200_impl::update_tick_rate(const double rate) +void b200_impl::set_auto_tick_rate( +        const double rate, +        const fs_path &tree_dsp_path, +        size_t num_chans +) { +    if (num_chans == 0) { // Divine them +        num_chans = std::max(size_t(1), max_chan_count()); +    } +    const double max_tick_rate = ad9361_device_t::AD9361_MAX_CLOCK_RATE/num_chans; +    if (rate != 0.0 and +        (uhd::math::fp_compare::fp_compare_delta<double>(rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) > +         uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ))) { +        throw uhd::value_error(str( +                boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate of %.2f MHz.") +                % (rate / 1e6) % (max_tick_rate / 1e6) +        )); +    } + +    // See also the doxygen documentation for these steps in b200_impl.hpp +    // Step 1: Obtain LCM and max rate from all relevant dsps +    boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5)); +    for (int i = 0; i < 2; i++) { // Loop through rx and tx +        std::string dir = (i == 0) ? "tx" : "rx"; +        // We have no way of knowing which DSPs are used, so we check them all. +        BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) { +            fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no); +            if (dsp_path == tree_dsp_path) { +                continue; +            } +            double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get(); +            // Check if the user selected something completely unreasonable: +            if (uhd::math::fp_compare::fp_compare_delta<double>(this_dsp_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) > +                uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ)) { +                throw uhd::value_error(str( +                        boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate of %.2f MHz.") +                        % (this_dsp_rate / 1e6) % (max_tick_rate / 1e6) +                )); +            } +            // If this_dsp_rate == 0.0, the sampling rate for this DSP hasn't been set, so +            // we don't take that into consideration. +            if (this_dsp_rate == 0.0) { +                continue; +            } +            lcm_rate = boost::math::lcm<boost::uint32_t>( +                    lcm_rate, +                    static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5)) +            ); +        } +    } +    if (lcm_rate == 1) { +        // In this case, no one has ever set a sampling rate. +        return; +    } + +    // Step 2: Check if the lcm_rate is within available limits: +    double base_rate = static_cast<double>(lcm_rate); +    if (uhd::math::fp_compare::fp_compare_delta<double>(base_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) > +        uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ)) { +        UHD_MSG(warning) +            << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl +            << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl; +        return; // Let the others handle this +    } + +    // Step 3: Choose the new rate +    // Rules for choosing the tick rate: +    // Choose a rate that is a power of 2 larger than the sampling rate, +    // but at least 4. Cannot exceed the max tick rate, of course, but must +    // be larger than the minimum tick rate. +    // An equation that does all that is: +    // +    // f_auto = r * 2^floor(log2(f_max/r)) +    //        = base_rate * multiplier +    // +    // where r is the base rate and f_max is the maximum tick rate. The case +    // where floor() yields 1 must be caught. +    const double min_tick_rate = _codec_ctrl->get_clock_rate_range().start(); +    // We use shifts here instead of 2^x because exp2() is not available in all compilers, +    // also this guarantees no rounding issues. The type cast to int32_t serves as floor(): +    boost::int32_t multiplier = (1 << boost::int32_t(uhd::math::log2(max_tick_rate / base_rate))); +    if (multiplier == 2 and base_rate >= min_tick_rate) { +        // Don't bother (see above) +        multiplier = 1; +    } +    double new_rate = base_rate * multiplier; +    UHD_ASSERT_THROW( +        uhd::math::fp_compare::fp_compare_delta<double>(new_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) >= +        uhd::math::fp_compare::fp_compare_delta<double>(min_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) +    ); +    UHD_ASSERT_THROW( +        uhd::math::fp_compare::fp_compare_delta<double>(new_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) <= +        uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) +    ); + +    if (!uhd::math::frequencies_are_equal(_tree->access<double>("/mboards/0/tick_rate").get(), new_rate)) { +        _tree->access<double>("/mboards/0/tick_rate").set(new_rate); +    } +} + +void b200_impl::update_tick_rate(const double new_tick_rate)  { -    check_tick_rate_with_current_streamers(rate); +    check_tick_rate_with_current_streamers(new_tick_rate);      BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)      {          boost::shared_ptr<sph::recv_packet_streamer> my_streamer =              boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock()); -        if (my_streamer) my_streamer->set_tick_rate(rate); -        perif.framer->set_tick_rate(_tick_rate); +        if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); +        perif.framer->set_tick_rate(new_tick_rate);      }      BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)      {          boost::shared_ptr<sph::send_packet_streamer> my_streamer =              boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); -        if (my_streamer) my_streamer->set_tick_rate(rate); -        perif.deframer->set_tick_rate(_tick_rate); +        if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); +        perif.deframer->set_tick_rate(new_tick_rate);      }  } +#define CHECK_RATE_AND_THROW(rate)  \ +        if (uhd::math::fp_compare::fp_compare_delta<double>(rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) > \ +            uhd::math::fp_compare::fp_compare_delta<double>(ad9361_device_t::AD9361_MAX_CLOCK_RATE, uhd::math::FREQ_COMPARISON_DELTA_HZ)) { \ +            throw uhd::value_error(str( \ +                    boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate.") \ +                    % (rate / 1e6) \ +            )); \ +        } + +double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate) +{ +    // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate +    if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { +        CHECK_RATE_AND_THROW(rx_rate); +        const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str(); +        set_auto_tick_rate(rx_rate, dsp_path); +    } +    return ddc->set_host_rate(rx_rate); +} +  #define CHECK_BANDWIDTH(dir) \      if (rate > _codec_ctrl->get_bw_filter_range(dir).stop()) { \          UHD_MSG(warning) \ @@ -108,6 +231,17 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)      CHECK_BANDWIDTH("Rx");  } +double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate) +{ +    // Have to set tick rate first, or the duc will change the requested rate based on default tick rate +    if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { +        CHECK_RATE_AND_THROW(tx_rate); +        const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str(); +        set_auto_tick_rate(tx_rate, dsp_path); +    } +    return duc->set_host_rate(tx_rate); +} +  void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)  {      boost::shared_ptr<sph::send_packet_streamer> my_streamer = @@ -276,6 +410,9 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)      if (args.otw_format.empty()) args.otw_format = "sc16";      args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; +    if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { +        set_auto_tick_rate(0, "", args.channels.size()); +    }      check_streamer_args(args, this->get_tick_rate(), "RX");      boost::shared_ptr<sph::recv_packet_streamer> my_streamer; @@ -383,7 +520,10 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_)      if (args.otw_format.empty()) args.otw_format = "sc16";      args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; -    check_streamer_args(args, this->get_tick_rate(), "TX"); +    if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { +        set_auto_tick_rate(0, "", args.channels.size()); +    } +    check_streamer_args(args, this->get_tick_rate(), "RX");      boost::shared_ptr<sph::send_packet_streamer> my_streamer;      for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) diff --git a/host/lib/usrp/b200/b200_regs.hpp b/host/lib/usrp/b200/b200_regs.hpp index 900651f94..8f2dd03f3 100644 --- a/host/lib/usrp/b200/b200_regs.hpp +++ b/host/lib/usrp/b200/b200_regs.hpp @@ -46,11 +46,13 @@ localparam SR_TX_DSP    = 184;  localparam SR_TIME      = 128;  localparam SR_RX_FMT    = 136;  localparam SR_TX_FMT    = 138; +localparam SR_FP_GPIO   = 200;  localparam RB32_TEST            = 0;  localparam RB64_TIME_NOW        = 8;  localparam RB64_TIME_PPS        = 16;  localparam RB64_CODEC_READBACK  = 24; +localparam RB32_FP_GPIO         = 32;  //pll constants  static const int AD9361_SLAVENO = (1 << 0); diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index 65e8e2df9..2d9f297b3 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -16,7 +16,6 @@  //  #include "ad9361_ctrl.hpp" -#include <uhd/exception.hpp>  #include <uhd/types/ranges.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/types/serial.hpp> @@ -108,6 +107,27 @@ public:          return _device.set_gain(direction, chain, value);      } +    void set_agc(const std::string &which, bool enable) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); +         _device.set_agc(chain, enable); +    } + +    void set_agc_mode(const std::string &which, const std::string &mode) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); +        ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); +        if(mode == "slow") { +            _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_SLOW_AGC); +        } else if (mode == "fast"){ +            _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_FAST_AGC); +        } else { +            throw uhd::runtime_error("ad9361_ctrl got an invalid AGC option."); +        } +    } +      //! set a new clock rate, return the exact value      double set_clock_rate(const double rate)      { @@ -175,6 +195,62 @@ public:          return sensor_value_t("RSSI", _device.get_rssi(chain), "dB");      } +    //! read the internal temp sensor. Average over 3 results +    sensor_value_t get_temperature() +    { +        return sensor_value_t("temp", _device.get_average_temperature(), "C"); +    } + +    void set_dc_offset_auto(const std::string &which, const bool on) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        _device.set_dc_offset_auto(direction,on); +    } + +    void set_iq_balance_auto(const std::string &which, const bool on) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        _device.set_iq_balance_auto(direction,on); +    } + +    double set_bw_filter(const std::string &which, const double bw) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        return _device.set_bw_filter(direction, bw); +    } + +    std::vector<std::string> get_filter_names(const std::string &which) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        return _device.get_filter_names(direction); +    } + +    filter_info_base::sptr get_filter(const std::string &which, const std::string &filter_name) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); +        return _device.get_filter(direction, chain, filter_name); +    } + +    void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr filter) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); +        ad9361_device_t::chain_t chain = _get_chain_from_antenna(which); +        _device.set_filter(direction, chain, filter_name, filter); +    } +  private:      static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna)      { diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index b7d7b8e26..ac0404b24 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -22,9 +22,13 @@  #include <uhd/types/ranges.hpp>  #include <uhd/types/serial.hpp>  #include <uhd/types/sensors.hpp> +#include <uhd/exception.hpp>  #include <boost/shared_ptr.hpp>  #include <ad9361_device.h>  #include <string> +#include <complex> +#include <uhd/types/filters.hpp> +#include <vector>  namespace uhd { namespace usrp { @@ -77,15 +81,18 @@ public:          return uhd::meta_range_t(5e6, ad9361_device_t::AD9361_MAX_CLOCK_RATE); //5 MHz DCM low end      } -    //! set the filter bandwidth for the frontend -    double set_bw_filter(const std::string &/*which*/, const double /*bw*/) -    { -        return 56e6; //TODO -    } +    //! set the filter bandwidth for the frontend's analog low pass +    virtual double set_bw_filter(const std::string &/*which*/, const double /*bw*/) = 0;      //! set the gain for a particular gain element      virtual double set_gain(const std::string &which, const double value) = 0; +    //! Enable or disable the AGC module +    virtual void set_agc(const std::string &which, bool enable) = 0; + +    //! configure the AGC module to slow or fast mode +    virtual void set_agc_mode(const std::string &which, const std::string &mode) = 0; +      //! set a new clock rate, return the exact value      virtual double set_clock_rate(const double rate) = 0; @@ -95,14 +102,46 @@ public:      //! tune the given frontend, return the exact value      virtual double tune(const std::string &which, const double value) = 0; +    //! set the DC offset for I and Q manually +    void set_dc_offset(const std::string &, const std::complex<double>) +    { +        //This feature should not be used according to Analog Devices +        throw uhd::runtime_error("ad9361_ctrl::set_dc_offset this feature is not supported on this device."); +    } + +    //! enable or disable the BB/RF DC tracking feature +    virtual void set_dc_offset_auto(const std::string &which, const bool on) = 0; + +    //! set the IQ correction value manually +    void set_iq_balance(const std::string &, const std::complex<double>) +    { +        //This feature should not be used according to Analog Devices +        throw uhd::runtime_error("ad9361_ctrl::set_iq_balance this feature is not supported on this device."); +    } + +    //! enable or disable the quadrature calibration +    virtual void set_iq_balance_auto(const std::string &which, const bool on) = 0; +      //! get the current frequency for the given frontend      virtual double get_freq(const std::string &which) = 0; -    //! turn on/off data port loopback +    //! turn on/off Catalina's data port loopback      virtual void data_port_loopback(const bool on) = 0;      //! read internal RSSI sensor      virtual sensor_value_t get_rssi(const std::string &which) = 0; + +    //! read the internal temp sensor +    virtual sensor_value_t get_temperature() = 0; + +    //! List all available filters by name +    virtual std::vector<std::string> get_filter_names(const std::string &which) = 0; + +    //! Return a list of all filters +    virtual filter_info_base::sptr get_filter(const std::string &which, const std::string &filter_name) = 0; + +    //! Write back a filter +    virtual void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr) = 0;  };  }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index db5de52d0..00534c305 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -11,6 +11,7 @@  #include <cmath>  #include <uhd/exception.hpp>  #include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp>  #include <boost/cstdint.hpp>  #include <boost/date_time/posix_time/posix_time.hpp>  #include <boost/thread/thread.hpp> @@ -78,6 +79,7 @@ int get_num_taps(int max_num_taps) {  const double ad9361_device_t::AD9361_MAX_GAIN        = 89.75;  const double ad9361_device_t::AD9361_MAX_CLOCK_RATE  = 61.44e6; +const double ad9361_device_t::AD9361_CAL_VALID_WINDOW = 100e6;  // Max bandwdith is due to filter rolloff in analog filter stage  const double ad9361_device_t::AD9361_RECOMMENDED_MAX_BANDWIDTH = 56e6; @@ -87,7 +89,7 @@ const double ad9361_device_t::AD9361_RECOMMENDED_MAX_BANDWIDTH = 56e6;   * how many taps are in the filter, and given a vector of the taps   * themselves.  */ -void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs) +void ad9361_device_t::_program_fir_filter(direction_t direction, chain_t chain, int num_taps, boost::uint16_t *coeffs)  {      boost::uint16_t base; @@ -102,8 +104,20 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b      /* Encode number of filter taps for programming register */      boost::uint8_t reg_numtaps = (((num_taps / 16) - 1) & 0x07) << 5; +    boost::uint8_t reg_chain = 0; +    switch (chain) { +    case CHAIN_1: +        reg_chain = 0x01 << 3; +        break; +    case CHAIN_2: +        reg_chain = 0x02 << 3; +        break; +    default: +        reg_chain = 0x03 << 3; +    } +      /* Turn on the filter clock. */ -    _io_iface->poke8(base + 5, reg_numtaps | 0x1a); +    _io_iface->poke8(base + 5, reg_numtaps | reg_chain | 0x02);      boost::this_thread::sleep(boost::posix_time::milliseconds(1));      /* Zero the unused taps just in case they have stale data */ @@ -112,7 +126,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b          _io_iface->poke8(base + 0, addr);          _io_iface->poke8(base + 1, 0x0);          _io_iface->poke8(base + 2, 0x0); -        _io_iface->poke8(base + 5, reg_numtaps | 0x1e); +        _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1) | (1 << 2));          _io_iface->poke8(base + 4, 0x00);          _io_iface->poke8(base + 4, 0x00);      } @@ -122,7 +136,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b          _io_iface->poke8(base + 0, addr);          _io_iface->poke8(base + 1, (coeffs[addr]) & 0xff);          _io_iface->poke8(base + 2, (coeffs[addr] >> 8) & 0xff); -        _io_iface->poke8(base + 5, reg_numtaps | 0x1e); +        _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1) | (1 << 2));          _io_iface->poke8(base + 4, 0x00);          _io_iface->poke8(base + 4, 0x00);      } @@ -133,9 +147,9 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b       before the clock stops. Wait 4 sample clock periods after setting D2 high while that data writes into the table"       */ -    _io_iface->poke8(base + 5, reg_numtaps | 0x1A); +    _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1));      if (direction == RX) { -        _io_iface->poke8(base + 5, reg_numtaps | 0x18); +        _io_iface->poke8(base + 5, reg_numtaps | reg_chain );          /* Rx Gain, set to prevent digital overflow/saturation in filters             0:+6dB, 1:0dB, 2:-6dB, 3:-12dB             page 35 of UG-671 */ @@ -144,7 +158,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b          /* Tx Gain. bit[0]. set to prevent digital overflow/saturation in filters             0: 0dB, 1:-6dB             page 25 of UG-671 */ -        _io_iface->poke8(base + 5, reg_numtaps | 0x18); +        _io_iface->poke8(base + 5, reg_numtaps | reg_chain );      }  } @@ -175,7 +189,7 @@ void ad9361_device_t::_setup_rx_fir(size_t num_taps, boost::int32_t decimation)          }      } -    _program_fir_filter(RX, num_taps, coeffs.get()); +    _program_fir_filter(RX, CHAIN_BOTH, num_taps, coeffs.get());  }  /* Program the TX FIR Filter. */ @@ -207,7 +221,7 @@ void ad9361_device_t::_setup_tx_fir(size_t num_taps, boost::int32_t interpolatio          }      } -    _program_fir_filter(TX, num_taps, coeffs.get()); +    _program_fir_filter(TX, CHAIN_BOTH, num_taps, coeffs.get());  }  /*********************************************************************** @@ -282,16 +296,24 @@ void ad9361_device_t::_calibrate_synth_charge_pumps()   *   * Note that the filter calibration depends heavily on the baseband   * bandwidth, so this must be re-done after any change to the RX sample - * rate. */ -double ad9361_device_t::_calibrate_baseband_rx_analog_filter() + * rate. + * UG570 Page 33 states that this filter should be calibrated to 1.4 * bbbw*/ +double ad9361_device_t::_calibrate_baseband_rx_analog_filter(double req_rfbw)  { -    /* For filter tuning, baseband BW is half the complex BW, and must be -     * between 28e6 and 0.2e6. */ -    double bbbw = _baseband_bw / 2.0; +    double bbbw = req_rfbw / 2.0; +    if(bbbw > _baseband_bw / 2.0) +    { +        UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw; +        bbbw = _baseband_bw / 2.0; +    } + +    /* Baseband BW must be between 28e6 and 0.143e6. +     * Max filter BW is 39.2 MHz. 39.2 / 1.4 = 28 +     * Min filter BW is 200kHz. 200 / 1.4 = 143 */      if (bbbw > 28e6) {          bbbw = 28e6; -    } else if (bbbw < 0.20e6) { -        bbbw = 0.20e6; +    } else if (bbbw < 0.143e6) { +        bbbw = 0.143e6;      }      double rxtune_clk = ((1.4 * bbbw * 2 * M_PI) / M_LN2); @@ -340,16 +362,25 @@ double ad9361_device_t::_calibrate_baseband_rx_analog_filter()   *   * Note that the filter calibration depends heavily on the baseband   * bandwidth, so this must be re-done after any change to the TX sample - * rate. */ -double ad9361_device_t::_calibrate_baseband_tx_analog_filter() + * rate. + * UG570 Page 32 states that this filter should be calibrated to 1.6 * bbbw*/ +double ad9361_device_t::_calibrate_baseband_tx_analog_filter(double req_rfbw)  { -    /* For filter tuning, baseband BW is half the complex BW, and must be -     * between 28e6 and 0.2e6. */ -    double bbbw = _baseband_bw / 2.0; +    double bbbw = req_rfbw / 2.0; + +    if(bbbw > _baseband_bw / 2.0) +    { +        UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw; +        bbbw = _baseband_bw / 2.0; +    } + +    /* Baseband BW must be between 20e6 and 0.391e6. +     * Max filter BW is 32 MHz. 32 / 1.6 = 20 +     * Min filter BW is 625 kHz. 625 / 1.6 = 391 */      if (bbbw > 20e6) {          bbbw = 20e6; -    } else if (bbbw < 0.625e6) { -        bbbw = 0.625e6; +    } else if (bbbw < 0.391e6) { +        bbbw = 0.391e6;      }      double txtune_clk = ((1.6 * bbbw * 2 * M_PI) / M_LN2); @@ -386,16 +417,25 @@ double ad9361_device_t::_calibrate_baseband_tx_analog_filter()  /* Calibrate the secondary TX filter.   *   * This filter also depends on the TX sample rate, so if a rate change is - * made, the previous calibration will no longer be valid. */ -void ad9361_device_t::_calibrate_secondary_tx_filter() + * made, the previous calibration will no longer be valid. + * UG570 Page 32 states that this filter should be calibrated to 5 * bbbw*/ +double ad9361_device_t::_calibrate_secondary_tx_filter(double req_rfbw)  { -    /* For filter tuning, baseband BW is half the complex BW, and must be -     * between 20e6 and 0.53e6. */ -    double bbbw = _baseband_bw / 2.0; +    double bbbw = req_rfbw / 2.0; + +    if(bbbw > _baseband_bw / 2.0) +    { +        UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw; +        bbbw = _baseband_bw / 2.0; +    } + +    /* Baseband BW must be between 20e6 and 0.54e6. +     * Max filter BW is 100 MHz. 100 / 5 = 20 +     * Min filter BW is 2.7 MHz. 2.7 / 5 = 0.54 */      if (bbbw > 20e6) {          bbbw = 20e6; -    } else if (bbbw < 0.53e6) { -        bbbw = 0.53e6; +    } else if (bbbw < 0.54e6) { +        bbbw = 0.54e6;      }      double bbbw_mhz = bbbw / 1e6; @@ -456,13 +496,17 @@ void ad9361_device_t::_calibrate_secondary_tx_filter()      _io_iface->poke8(0x0d2, reg0d2);      _io_iface->poke8(0x0d1, reg0d1);      _io_iface->poke8(0x0d0, reg0d0); + +    return bbbw;  }  /* Calibrate the RX TIAs.   *   * Note that the values in the TIA register, after calibration, vary with - * the RX gain settings. */ -void ad9361_device_t::_calibrate_rx_TIAs() + * the RX gain settings. + * We do not really program the BW here. Most settings are taken form the BB LPF registers + * UG570 page 33 states that this filter should be calibrated to 2.5 * bbbw */ +double ad9361_device_t::_calibrate_rx_TIAs(double req_rfbw)  {      boost::uint8_t reg1eb = _io_iface->peek8(0x1eb) & 0x3F;      boost::uint8_t reg1ec = _io_iface->peek8(0x1ec) & 0x7F; @@ -473,13 +517,21 @@ void ad9361_device_t::_calibrate_rx_TIAs()      boost::uint8_t reg1de = 0x00;      boost::uint8_t reg1df = 0x00; -    /* For calibration, baseband BW is half the complex BW, and must be -     * between 28e6 and 0.2e6. */ -    double bbbw = _baseband_bw / 2.0; -    if (bbbw > 20e6) { -        bbbw = 20e6; -    } else if (bbbw < 0.20e6) { -        bbbw = 0.20e6; +    double bbbw = req_rfbw / 2.0; + +    if(bbbw > _baseband_bw / 2.0) +    { +        UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw; +        bbbw = _baseband_bw / 2.0; +    } + +    /* Baseband BW must be between 28e6 and 0.4e6. +     * Max filter BW is 70 MHz. 70 / 2.5 = 28 +     * Min filter BW is 1 MHz. 1 / 2.5 =  0.4*/ +    if (bbbw > 28e6) { +        bbbw = 28e6; +    } else if (bbbw < 0.40e6) { +        bbbw = 0.40e6;      }      double ceil_bbbw_mhz = std::ceil(bbbw / 1e6); @@ -520,6 +572,8 @@ void ad9361_device_t::_calibrate_rx_TIAs()      _io_iface->poke8(0x1df, reg1df);      _io_iface->poke8(0x1dc, reg1dc);      _io_iface->poke8(0x1de, reg1de); + +    return bbbw;  }  /* Setup the AD9361 ADC. @@ -651,11 +705,12 @@ void ad9361_device_t::_setup_adc()  }  /* Calibrate the baseband DC offset. - * - * Note that this function is called from within the TX quadrature - * calibration function! */ + * Disables tracking + */  void ad9361_device_t::_calibrate_baseband_dc_offset()  { +    _io_iface->poke8(0x18b, 0x83); //Reset RF DC tracking flag +      _io_iface->poke8(0x193, 0x3f); // Calibration settings      _io_iface->poke8(0x190, 0x0f); // Set tracking coefficient      //write_ad9361_reg(device, 0x190, /*0x0f*//*0xDF*/0x80*1 | 0x40*1 | (16+8/*+4*/)); // Set tracking coefficient: don't *4 counter, do decim /4, increased gain shift @@ -675,9 +730,8 @@ void ad9361_device_t::_calibrate_baseband_dc_offset()  }  /* Calibrate the RF DC offset. - * - * Note that this function is called from within the TX quadrature - * calibration function. */ + * Disables tracking + */  void ad9361_device_t::_calibrate_rf_dc_offset()  {      /* Some settings are frequency-dependent. */ @@ -692,7 +746,7 @@ void ad9361_device_t::_calibrate_rf_dc_offset()      }      _io_iface->poke8(0x185, 0x20); // RF DC Offset wait count -    _io_iface->poke8(0x18b, 0x83); +    _io_iface->poke8(0x18b, 0x83); // Disable tracking      _io_iface->poke8(0x189, 0x30);      /* Run the calibration! */ @@ -708,6 +762,16 @@ void ad9361_device_t::_calibrate_rf_dc_offset()      }  } +void ad9361_device_t::_configure_bb_rf_dc_tracking(const bool on) +{ +    if(on) +    { +        _io_iface->poke8(0x18b, 0xad); // Enable BB and RF DC tracking +    } else { +        _io_iface->poke8(0x18b, 0x83); // Disable BB and RF DC tracking +    } +} +  /* Start the RX quadrature calibration.   *   * Note that we are using AD9361's 'tracking' feature for RX quadrature @@ -719,17 +783,21 @@ void ad9361_device_t::_calibrate_rx_quadrature()      _io_iface->poke8(0x168, 0x03); // Set tone level for cal      _io_iface->poke8(0x16e, 0x25); // RX Gain index to use for cal      _io_iface->poke8(0x16a, 0x75); // Set Kexp phase -    _io_iface->poke8(0x16b, 0x15); // Set Kexp amplitude -    _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode -    _io_iface->poke8(0x18b, 0xad); +    _io_iface->poke8(0x16b, 0x95); // Set Kexp amplitude + +    if(_use_iq_balance_correction) +    { +        _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode. Gets disabled in _tx_quadrature_cal_routine! +    }  } -/* TX quadtrature calibration routine. +/* TX quadrature calibration routine.   *   * The TX quadrature needs to be done twice, once for each TX chain, with   * only one register change in between. Thus, this function enacts the   * calibrations, and it is called from calibrate_tx_quadrature. */  void ad9361_device_t::_tx_quadrature_cal_routine() { +      /* This is a weird process, but here is how it works:       * 1) Read the calibrated NCO frequency bits out of 0A3.       * 2) Write the two bits to the RX NCO freq part of 0A0. @@ -765,7 +833,7 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {      /* The gain table index used for calibration must be adjusted for the       * mid-table to get a TIA index = 1 and LPF index = 0. */ -    if ((_rx_freq >= 1300e6) && (_rx_freq < 4000e6)) { +    if (_rx_freq < 1300e6) {          _io_iface->poke8(0x0aa, 0x22); // Cal gain table index      } else {          _io_iface->poke8(0x0aa, 0x25); // Cal gain table index @@ -774,12 +842,6 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {      _io_iface->poke8(0x0a4, 0xf0); // Cal setting conut      _io_iface->poke8(0x0ae, 0x00); // Cal LPF gain index (split mode) -    /* First, calibrate the baseband DC offset. */ -    _calibrate_baseband_dc_offset(); - -    /* Second, calibrate the RF DC offset. */ -    _calibrate_rf_dc_offset(); -      /* Now, calibrate the TX quadrature! */      size_t count = 0;      _io_iface->poke8(0x016, 0x10); @@ -794,9 +856,7 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {  }  /* Run the TX quadrature calibration. - * - * Note that from within this function we are also triggering the baseband - * and RF DC calibrations. */ + */  void ad9361_device_t::_calibrate_tx_quadrature()  {      /* Make sure we are, in fact, in the ALERT state. If not, something is @@ -880,7 +940,7 @@ void ad9361_device_t::_program_mixer_gm_subtable()  void ad9361_device_t::_program_gain_table() {      /* Figure out which gain table we should be using for our current       * frequency band. */ -    boost::uint8_t (*gain_table)[5] = NULL; +    boost::uint8_t (*gain_table)[3] = NULL;      boost::uint8_t new_gain_table;      if (_rx_freq < 1300e6) {          gain_table = gain_table_sub_1300mhz; @@ -911,9 +971,9 @@ void ad9361_device_t::_program_gain_table() {      boost::uint8_t index = 0;      for (; index < 77; index++) {          _io_iface->poke8(0x130, index); -        _io_iface->poke8(0x131, gain_table[index][1]); -        _io_iface->poke8(0x132, gain_table[index][2]); -        _io_iface->poke8(0x133, gain_table[index][3]); +        _io_iface->poke8(0x131, gain_table[index][0]); +        _io_iface->poke8(0x132, gain_table[index][1]); +        _io_iface->poke8(0x133, gain_table[index][2]);          _io_iface->poke8(0x137, 0x1E);          _io_iface->poke8(0x134, 0x00);          _io_iface->poke8(0x134, 0x00); @@ -939,28 +999,58 @@ void ad9361_device_t::_program_gain_table() {  /* Setup gain control registers.   * - * This really only needs to be done once, at initialization. */ -void ad9361_device_t::_setup_gain_control() + * This really only needs to be done once, at initialization. + * If AGC is used the mode select bits (Reg 0x0FA) must be written manually */ +void ad9361_device_t::_setup_gain_control(bool agc)  { -    _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select -    _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl -    _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size -    _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index -    _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time -    _io_iface->poke8(0x100, 0x6F); // Max Digital Gain -    _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold -    _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold -    _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold -    _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold -    _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index -    _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index -    _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index -    _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index -    _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index -    _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index -    _io_iface->poke8(0x114, 0x30); // Low Power Threshold -    _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit -    _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control +    /* The AGC mode configuration should be good for all cases. +     * However, non AGC configuration still used for backward compatibility. */ +    if (agc) { +        /*mode select bits must be written before hand!*/ +        _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl +        _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size +        _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index +        _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time +        _io_iface->poke8(0x100, 0x6F); // Max Digital Gain +        _io_iface->poke8(0x101, 0x0A); // Max Digital Gain +        _io_iface->poke8(0x103, 0x08); // Max Digital Gain +        _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold +        _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold +        _io_iface->poke8(0x106, 0x22); // Max Digital Gain +        _io_iface->poke8(0x107, 0x2B); // Large LMT Overload Threshold +        _io_iface->poke8(0x108, 0x31); +        _io_iface->poke8(0x111, 0x0A); +        _io_iface->poke8(0x11A, 0x1C); +        _io_iface->poke8(0x120, 0x0C); +        _io_iface->poke8(0x121, 0x44); +        _io_iface->poke8(0x122, 0x44); +        _io_iface->poke8(0x123, 0x11); +        _io_iface->poke8(0x124, 0xF5); +        _io_iface->poke8(0x125, 0x3B); +        _io_iface->poke8(0x128, 0x03); +        _io_iface->poke8(0x129, 0x56); +        _io_iface->poke8(0x12A, 0x22); +    } else { +        _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select +        _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl +        _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size +        _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index +        _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time +        _io_iface->poke8(0x100, 0x6F); // Max Digital Gain +        _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold +        _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold +        _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold +        _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold +        _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index +        _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index +        _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index +        _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index +        _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index +        _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index +        _io_iface->poke8(0x114, 0x30); // Low Power Threshold +        _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit +        _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control +    }  }  /* Setup the RX or TX synthesizers. @@ -1257,6 +1347,7 @@ double ad9361_device_t::_setup_rates(const double rate)      int divfactor = 0;      _tfir_factor = 0;      _rfir_factor = 0; +      if (rate < 0.33e6) {          // RX1 + RX2 enabled, 3, 2, 2, 4          _regs.rxfilt = B8(11101111); @@ -1412,6 +1503,19 @@ void ad9361_device_t::initialize()      _rx2_gain = 0;      _tx1_gain = 0;      _tx2_gain = 0; +    _use_dc_offset_correction = true; +    _use_iq_balance_correction = true; +    _rx1_agc_mode = GAIN_MODE_SLOW_AGC; +    _rx2_agc_mode = GAIN_MODE_SLOW_AGC; +    _rx1_agc_enable = false; +    _rx2_agc_enable = false; +    _last_calibration_freq = -AD9361_CAL_VALID_WINDOW; +    _rx_analog_bw = 0; +    _tx_analog_bw = 0; +    _rx_tia_lp_bw = 0; +    _tx_sec_lp_bw = 0; +    _rx_bb_lp_bw = 0; +    _tx_bb_lp_bw = 0;      /* Reset the device. */      _io_iface->poke8(0x000, 0x01); @@ -1490,7 +1594,6 @@ void ad9361_device_t::initialize()      _io_iface->poke8(0x019, 0x00); // AuxDAC2 Word[9:2]      _io_iface->poke8(0x01A, 0x00); // AuxDAC1 Config and Word[1:0]      _io_iface->poke8(0x01B, 0x00); // AuxDAC2 Config and Word[1:0] -    _io_iface->poke8(0x022, 0x4A); // Invert Bypassed LNA      _io_iface->poke8(0x023, 0xFF); // AuxDAC Manaul/Auto Control      _io_iface->poke8(0x026, 0x00); // AuxDAC Manual Select Bit/GPO Manual Select      _io_iface->poke8(0x030, 0x00); // AuxDAC1 Rx Delay @@ -1498,10 +1601,18 @@ void ad9361_device_t::initialize()      _io_iface->poke8(0x032, 0x00); // AuxDAC2 Rx Delay      _io_iface->poke8(0x033, 0x00); // AuxDAC2 Tx Delay +    /* LNA bypass polarity inversion +     *     According to the register map, we should invert the bypass path to +     *     match LNA phase. Extensive testing, however, shows otherwise and that +     *     to align bypass and LNA phases, the bypass inversion switch should be +     *     turned off. +     */ +    _io_iface->poke8(0x022, 0x0A); +      /* Setup AuxADC */      _io_iface->poke8(0x00B, 0x00); // Temp Sensor Setup (Offset)      _io_iface->poke8(0x00C, 0x00); // Temp Sensor Setup (Temp Window) -    _io_iface->poke8(0x00D, 0x03); // Temp Sensor Setup (Periodic Measure) +    _io_iface->poke8(0x00D, 0x00); // Temp Sensor Setup (Manual  Measure)      _io_iface->poke8(0x00F, 0x04); // Temp Sensor Setup (Decimation)      _io_iface->poke8(0x01C, 0x10); // AuxADC Setup (Clock Div)      _io_iface->poke8(0x01D, 0x01); // AuxADC Setup (Decimation/Enable) @@ -1555,17 +1666,18 @@ void ad9361_device_t::initialize()      _program_mixer_gm_subtable();      _program_gain_table(); -    _setup_gain_control(); +    _setup_gain_control(false); -    _calibrate_baseband_rx_analog_filter(); -    _calibrate_baseband_tx_analog_filter(); -    _calibrate_rx_TIAs(); -    _calibrate_secondary_tx_filter(); +    set_bw_filter(RX, _baseband_bw); +    set_bw_filter(TX, _baseband_bw);      _setup_adc(); +    _calibrate_baseband_dc_offset(); +    _calibrate_rf_dc_offset();      _calibrate_tx_quadrature();      _calibrate_rx_quadrature(); +    _configure_bb_rf_dc_tracking(_use_dc_offset_correction);      // cals done, set PPORT config      switch (_client_params->get_digital_interface_mode()) { @@ -1680,18 +1792,19 @@ double ad9361_device_t::set_clock_rate(const double req_rate)      _program_mixer_gm_subtable();      _program_gain_table(); -    _setup_gain_control(); +    _setup_gain_control(false);      _reprogram_gains(); -    _calibrate_baseband_rx_analog_filter(); -    _calibrate_baseband_tx_analog_filter(); -    _calibrate_rx_TIAs(); -    _calibrate_secondary_tx_filter(); +    set_bw_filter(RX, _baseband_bw); +    set_bw_filter(TX, _baseband_bw);      _setup_adc(); +    _calibrate_baseband_dc_offset(); +    _calibrate_rf_dc_offset();      _calibrate_tx_quadrature();      _calibrate_rx_quadrature(); +    _configure_bb_rf_dc_tracking(_use_dc_offset_correction);      // cals done, set PPORT config      switch (_client_params->get_digital_interface_mode()) { @@ -1843,9 +1956,16 @@ double ad9361_device_t::tune(direction_t direction, const double value)      /* Update the gain settings. */      _reprogram_gains(); -    /* Run the calibration algorithms. */ -    _calibrate_tx_quadrature(); -    _calibrate_rx_quadrature(); +    /* Only run the following calibrations if we are more than 100MHz away +     * from the previous calibration point. */ +    if (std::abs(_last_calibration_freq - tune_freq) > AD9361_CAL_VALID_WINDOW) { +        /* Run the calibration algorithms. */ +        _calibrate_rf_dc_offset(); +        _calibrate_tx_quadrature(); +        _calibrate_rx_quadrature(); +        _configure_bb_rf_dc_tracking(_use_dc_offset_correction); +        _last_calibration_freq = tune_freq; +    }      /* If we were in the FDD state, return it now. */      if (not_in_alert) { @@ -1960,4 +2080,678 @@ double ad9361_device_t::get_rssi(chain_t chain)      return rssi;  } +/* + * Returns the reading of the internal temperature sensor. + * One point calibration of the sensor was done according to datasheet + * leading to the given default constant correction factor. + */ +double ad9361_device_t::_get_temperature(const double cal_offset, const double timeout) +{ +    //set 0x01D[0] to 1 to disable AuxADC GPIO reading +    boost::uint8_t tmp = 0; +    tmp = _io_iface->peek8(0x01D); +    _io_iface->poke8(0x01D, (tmp | 0x01)); +    _io_iface->poke8(0x00B, 0); //set offset to 0 + +    _io_iface->poke8(0x00C, 0x01); //start reading, clears bit 0x00C[1] +    boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); +    boost::posix_time::time_duration elapsed; +    //wait for valid data (toggle of bit 1 in 0x00C) +    while(((_io_iface->peek8(0x00C) >> 1) & 0x01) == 0) { +        boost::this_thread::sleep(boost::posix_time::microseconds(100)); +        elapsed = boost::posix_time::microsec_clock::local_time() - start_time; +        if(elapsed.total_milliseconds() > (timeout*1000)) +        { +            throw uhd::runtime_error("[ad9361_device_t] timeout while reading temperature"); +        } +    } +    _io_iface->poke8(0x00C, 0x00); //clear read flag + +    boost::uint8_t temp = _io_iface->peek8(0x00E); //read temperature. +    double tmp_temp = temp/1.140f; //according to ADI driver +    tmp_temp = tmp_temp + cal_offset; //Constant offset acquired by one point calibration. + +    return tmp_temp; +} + +double ad9361_device_t::get_average_temperature(const double cal_offset, const size_t num_samples) +{ +    double d_temp = 0; +    for(size_t i = 0; i < num_samples; i++) { +        double tmp_temp = _get_temperature(cal_offset); +        d_temp += (tmp_temp/num_samples); +    } +    return d_temp; +} + +void ad9361_device_t::set_dc_offset_auto(direction_t direction, const bool on) +{ +    if(direction == RX) +    { +         _use_dc_offset_correction = on; +         _configure_bb_rf_dc_tracking(_use_dc_offset_correction); +        if(on) +        { +            _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2))))); //Clear force bits +            //Do a single shot DC offset cal before enabling tracking (Not possible if not in ALERT state. Is it necessary?) +        } else { +            //clear current config values +            _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2)))); //Set input A and input B&C force enable bits +            _io_iface->poke8(0x174, 0x00); +            _io_iface->poke8(0x175, 0x00); +            _io_iface->poke8(0x176, 0x00); +            _io_iface->poke8(0x177, 0x00); +            _io_iface->poke8(0x178, 0x00); +            _io_iface->poke8(0x17D, 0x00); +            _io_iface->poke8(0x17E, 0x00); +            _io_iface->poke8(0x17F, 0x00); +            _io_iface->poke8(0x180, 0x00); +            _io_iface->poke8(0x181, 0x00); +        } +    } else { +        // DC offset is removed during TX quad cal +        throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH"); +    } +} + +void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on) +{ +    if(direction == RX) +    { +        _use_iq_balance_correction = on; +        if(on) +        { +            //disable force registers and enable tracking +            _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~ ( (1<<1) | (1<<0) | (1<<5) | (1<<4) )))); +            _calibrate_rx_quadrature(); +        } else { +            //disable IQ tracking +            _io_iface->poke8(0x169, 0xc0); +            //clear current config values +            _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 1) | (1 << 0) | (1 << 5) | (1 << 4)))); //Set Rx2 input B&C force enable bit +            _io_iface->poke8(0x17B, 0x00); +            _io_iface->poke8(0x17C, 0x00); +            _io_iface->poke8(0x179, 0x00); +            _io_iface->poke8(0x17A, 0x00); +            _io_iface->poke8(0x170, 0x00); +            _io_iface->poke8(0x171, 0x00); +            _io_iface->poke8(0x172, 0x00); +            _io_iface->poke8(0x173, 0x00); +        } +    } else { +        throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH"); +    } +} + +/* Sets the RX gain mode to be used. + * If a transition from an AGC to an non AGC mode occurs (or vice versa) + * the gain configuration will be reloaded. */ +void ad9361_device_t::_setup_agc(chain_t chain, gain_mode_t gain_mode) +{ +    boost::uint8_t gain_mode_reg = 0; +    boost::uint8_t gain_mode_prev = 0; +    boost::uint8_t gain_mode_bits_pos = 0; + +    gain_mode_reg = _io_iface->peek8(0x0FA); +    gain_mode_prev = (gain_mode_reg & 0x0F); + +    if (chain == CHAIN_1) { +        gain_mode_bits_pos = 0; +    } else if (chain == CHAIN_2) { +        gain_mode_bits_pos = 2; +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } + +    gain_mode_reg = (gain_mode_reg & (~(0x03<<gain_mode_bits_pos))); //clear mode bits +    switch (gain_mode) { +        case GAIN_MODE_MANUAL: +            //leave bits cleared +            break; +        case GAIN_MODE_SLOW_AGC: +            gain_mode_reg = (gain_mode_reg | (0x02<<gain_mode_bits_pos)); +            break; +        case GAIN_MODE_FAST_AGC: +            gain_mode_reg = (gain_mode_reg | (0x01<<gain_mode_bits_pos)); +            break; +        default: +            throw uhd::runtime_error("[ad9361_device_t] Gain mode does not exist"); +    } +    _io_iface->poke8(0x0FA, gain_mode_reg); +    boost::uint8_t gain_mode_status = _io_iface->peek8(0x0FA); +    gain_mode_status = (gain_mode_status & 0x0F); +    /*Check if gain mode configuration needs to be reprogrammed*/ +    if (((gain_mode_prev == 0) && (gain_mode_status != 0)) || ((gain_mode_prev != 0) && (gain_mode_status == 0))) { +        if (gain_mode_status == 0) { +            /*load manual mode config*/ +            _setup_gain_control(false); +        } else { +            /*load agc mode config*/ +            _setup_gain_control(true); +        } +    } +} + +void ad9361_device_t::set_agc(chain_t chain, bool enable) +{ +    if(chain == CHAIN_1) { +        _rx1_agc_enable = enable; +        if(enable) { +            _setup_agc(chain, _rx1_agc_mode); +        } else { +            _setup_agc(chain, GAIN_MODE_MANUAL); +        } +    } else if (chain == CHAIN_2){ +        _rx2_agc_enable = enable; +        if(enable) { +            _setup_agc(chain, _rx2_agc_mode); +        } else { +            _setup_agc(chain, GAIN_MODE_MANUAL); +        } +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } +} + +void ad9361_device_t::set_agc_mode(chain_t chain, gain_mode_t gain_mode) +{ +    if(chain == CHAIN_1) { +        _rx1_agc_mode = gain_mode; +        if(_rx1_agc_enable) { +            _setup_agc(chain, _rx1_agc_mode); +        } +    } else if(chain == CHAIN_2){ +        _rx2_agc_mode = gain_mode; +        if(_rx2_agc_enable) { +            _setup_agc(chain, _rx2_agc_mode); +        } +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } +} + +std::vector<std::string> ad9361_device_t::get_filter_names(direction_t direction) +{ +    std::vector<std::string> ret; +    if(direction == RX) { +        for(std::map<std::string, filter_query_helper>::iterator it = _rx_filters.begin(); it != _rx_filters.end(); ++it) { +            ret.push_back(it->first); +        } +    } else if (direction == TX) +    { +        for(std::map<std::string, filter_query_helper>::iterator it = _tx_filters.begin(); it != _tx_filters.end(); ++it) { +            ret.push_back(it->first); +        } +    } +    return ret; +} + +filter_info_base::sptr ad9361_device_t::get_filter(direction_t direction, chain_t chain, const std::string &name) +{ +    if(direction == RX) { +        if (not _rx_filters[name].get) +        { +            throw uhd::runtime_error("ad9361_device_t::get_filter this filter can not be read."); +        } +        return _rx_filters[name].get(direction, chain); +    } else if (direction == TX) { +        if (not _tx_filters[name].get) +        { +            throw uhd::runtime_error("ad9361_device_t::get_filter this filter can not be read."); +        } +        return _tx_filters[name].get(direction, chain); +    } + +    throw uhd::runtime_error("ad9361_device_t::get_filter wrong direction parameter."); +} + +void ad9361_device_t::set_filter(direction_t direction, chain_t chain, const std::string &name, filter_info_base::sptr filter) +{ + +    if(direction == RX) { +        if(not _rx_filters[name].set) +        { +            throw uhd::runtime_error("ad9361_device_t::set_filter this filter can not be written."); +        } +        _rx_filters[name].set(direction, chain, filter); +    } else if (direction == TX) { +        if(not _tx_filters[name].set) +        { +            throw uhd::runtime_error("ad9361_device_t::set_filter this filter can not be written."); +        } +        _tx_filters[name].set(direction, chain, filter); +    } + +} + +double ad9361_device_t::set_bw_filter(direction_t direction, const double rf_bw) +{ +    //both low pass filters are programmed to the same bw. However, their cutoffs will differ. +    //Together they should create the requested bb bw. +    double set_analog_bb_bw = 0; +    if(direction == RX) +    { +        _rx_bb_lp_bw = _calibrate_baseband_rx_analog_filter(rf_bw); //returns bb bw +        _rx_tia_lp_bw = _calibrate_rx_TIAs(rf_bw); +        _rx_analog_bw = _rx_bb_lp_bw; +        set_analog_bb_bw = _rx_analog_bw; +    } else { +        _tx_bb_lp_bw = _calibrate_baseband_tx_analog_filter(rf_bw); //returns bb bw +        _tx_sec_lp_bw = _calibrate_secondary_tx_filter(rf_bw); +        _tx_analog_bw = _tx_bb_lp_bw; +        set_analog_bb_bw = _tx_analog_bw; +    } +    return (2.0 * set_analog_bb_bw); +} + +void ad9361_device_t::_set_fir_taps(direction_t direction, chain_t chain, const std::vector<boost::int16_t>& taps) +{ +    size_t num_taps = taps.size(); +    size_t num_taps_avail = _get_num_fir_taps(direction); +    if(num_taps == num_taps_avail) +    { +        boost::scoped_array<boost::uint16_t> coeffs(new boost::uint16_t[num_taps_avail]); +        for (size_t i = 0; i < num_taps_avail; i++) +        { +            coeffs[i] = boost::uint16_t(taps[i]); +        } +        _program_fir_filter(direction, chain, num_taps_avail, coeffs.get()); +    } else if(num_taps < num_taps_avail){ +        throw uhd::runtime_error("ad9361_device_t::_set_fir_taps not enough coefficients."); +    } else { +        throw uhd::runtime_error("ad9361_device_t::_set_fir_taps too many coefficients."); +    } +} + +size_t ad9361_device_t::_get_num_fir_taps(direction_t direction) +{ +    boost::uint8_t num = 0; +    if(direction == RX) +        num = _io_iface->peek8(0x0F5); +    else +        num = _io_iface->peek8(0x065); +    num = ((num >> 5) & 0x07); +    return ((num + 1) * 16); +} + +size_t ad9361_device_t::_get_fir_dec_int(direction_t direction) +{ +    boost::uint8_t dec_int = 0; +    if(direction == RX) +        dec_int = _io_iface->peek8(0x003); +    else +        dec_int = _io_iface->peek8(0x002); +    /* +     * 0 = dec/int by 1 and bypass filter +     * 1 = dec/int by 1 +     * 2 = dec/int by 2 +     * 3 = dec/int by 4 */ +    dec_int = (dec_int & 0x03); +    if(dec_int == 3) +    { +        return 4; +    } +    return dec_int; +} + +std::vector<boost::int16_t> ad9361_device_t::_get_fir_taps(direction_t direction, chain_t chain) +{ +    int base; +    size_t num_taps = _get_num_fir_taps(direction); +    boost::uint8_t config; +    boost::uint8_t reg_numtaps = (((num_taps / 16) - 1) & 0x07) << 5; +    config = reg_numtaps | 0x02; //start the programming clock + +    if(chain == CHAIN_1) +    { +        config = config | (1 << 3); +    } else if (chain == CHAIN_2){ +        config = config | (1 << 4); +    } else { +        throw uhd::runtime_error("[ad9361_device_t] Can not read both chains synchronously"); +    } + +    if(direction == RX) +    { +        base = 0xF0; +    } else { +        base = 0x60; +    } + +    _io_iface->poke8(base+5,config); + +    std::vector<boost::int16_t> taps; +    boost::uint8_t lower_val; +    boost::uint8_t higher_val; +    boost::uint16_t coeff; +    for(size_t i = 0;i < num_taps;i++) +    { +        _io_iface->poke8(base,0x00+i); +        lower_val = _io_iface->peek8(base+3); +        higher_val = _io_iface->peek8(base+4); +        coeff = ((higher_val << 8) | lower_val); +        taps.push_back(boost::int16_t(coeff)); +    } + +    config = (config & (~(1 << 1))); //disable filter clock +    _io_iface->poke8(base+5,config); +    return taps; +} + +/* + * Returns either RX TIA LPF or TX Secondary LPF + * depending on the direction. + * See UG570 for details on used scaling factors. */ +filter_info_base::sptr ad9361_device_t::_get_filter_lp_tia_sec(direction_t direction) +{ +    double cutoff = 0; + +    if(direction == RX) +    { +       cutoff = 2.5 * _rx_tia_lp_bw; +    } else { +       cutoff = 5 * _tx_sec_lp_bw; +    } + +    filter_info_base::sptr lp(new analog_filter_lp(filter_info_base::ANALOG_LOW_PASS, false, 0, "single-pole", cutoff, 20)); +    return  lp; +} + +/* + * Returns RX/TX BB LPF. + * See UG570 for details on used scaling factors. */ +filter_info_base::sptr ad9361_device_t::_get_filter_lp_bb(direction_t direction) +{ +    double cutoff = 0; +    if(direction == RX) +    { +        cutoff = 1.4 * _rx_bb_lp_bw; +    } else { +        cutoff = 1.6 * _tx_bb_lp_bw; +    } + +    filter_info_base::sptr bb_lp(new analog_filter_lp(filter_info_base::ANALOG_LOW_PASS, false, 1, "third-order Butterworth", cutoff, 60)); +    return  bb_lp; +} + +/* + * For RX direction the DEC3 is returned. + * For TX direction the INT3 is returned. */ +filter_info_base::sptr ad9361_device_t::_get_filter_dec_int_3(direction_t direction) +{ +    boost::uint8_t enable = 0; +    double rate = _adcclock_freq; +    double full_scale; +    size_t dec = 0; +    size_t interpol = 0; +    filter_info_base::filter_type type = filter_info_base::DIGITAL_I16; +    std::string name; +    boost::int16_t taps_array_rx[] = {55, 83, 0, -393, -580, 0, 1914, 4041, 5120, 4041, 1914, 0, -580, -393, 0, 83, 55}; +    boost::int16_t taps_array_tx[] = {36, -19, 0, -156, -12, 0, 479, 233, 0, -1215, -993, 0, 3569, 6277, 8192, 6277, 3569, 0, -993, -1215, 0, 223, 479, 0, -12, -156, 0, -19, 36}; +    std::vector<boost::int16_t> taps; + +    filter_info_base::sptr ret; + +    if(direction == RX) +    { +        full_scale = 16384; +        dec = 3; +        interpol = 1; + +        enable = _io_iface->peek8(0x003); +        enable = ((enable >> 4) & 0x03); +        taps.assign(taps_array_rx, taps_array_rx + sizeof(taps_array_rx) / sizeof(boost::int16_t) ); + +    } else { +        full_scale = 8192; +        dec = 1; +        interpol = 3; + +        boost::uint8_t use_dac_clk_div = _io_iface->peek8(0x00A); +        use_dac_clk_div = ((use_dac_clk_div >> 3) & 0x01); +        if(use_dac_clk_div == 1) +        { +            rate = rate / 2; +        } + +        enable = _io_iface->peek8(0x002); +        enable = ((enable >> 4) & 0x03); +        if(enable == 2) //0 => int. by 1, 1 => int. by 2 (HB3), 2 => int. by 3 +        { +            rate /= 3; +        } + +        taps.assign(taps_array_tx, taps_array_tx + sizeof(taps_array_tx) / sizeof(boost::int16_t) ); +    } + +    ret = filter_info_base::sptr(new digital_filter_base<boost::int16_t>(type, (enable != 2) ? true : false, 2, rate, interpol, dec, full_scale, taps.size(), taps)); +    return  ret; +} + +filter_info_base::sptr ad9361_device_t::_get_filter_hb_3(direction_t direction) +{ +    boost::uint8_t enable = 0; +    double rate = _adcclock_freq; +    double full_scale = 0; +    size_t dec = 1; +    size_t interpol = 1; +    filter_info_base::filter_type type = filter_info_base::DIGITAL_I16; +    boost::int16_t taps_array_rx[] = {1, 4, 6, 4, 1}; +    boost::int16_t taps_array_tx[] = {1, 2, 1}; +    std::vector<boost::int16_t> taps; + +    if(direction == RX) +    { +        full_scale = 16; +        dec = 2; + +        enable = _io_iface->peek8(0x003); +        enable = ((enable >> 4) & 0x03); +        taps.assign(taps_array_rx, taps_array_rx + sizeof(taps_array_rx) / sizeof(boost::int16_t) ); +    } else { +        full_scale = 2; +        interpol = 2; + +        boost::uint8_t use_dac_clk_div = _io_iface->peek8(0x00A); +        use_dac_clk_div = ((use_dac_clk_div >> 3) & 0x01); +        if(use_dac_clk_div == 1) +        { +            rate = rate / 2; +        } + +        enable = _io_iface->peek8(0x002); +        enable = ((enable >> 4) & 0x03); +        if(enable == 1) +        { +            rate /= 2; +        } +        taps.assign(taps_array_tx, taps_array_tx + sizeof(taps_array_tx) / sizeof(boost::int16_t) ); +    } + +    filter_info_base::sptr hb = filter_info_base::sptr(new digital_filter_base<boost::int16_t>(type, (enable != 1) ? true : false, 2, rate, interpol, dec, full_scale, taps.size(), taps)); +    return  hb; +} + +filter_info_base::sptr ad9361_device_t::_get_filter_hb_2(direction_t direction) +{ +    boost::uint8_t enable = 0; +    double rate = _adcclock_freq; +    double full_scale = 0; +    size_t dec = 1; +    size_t interpol = 1; +    filter_info_base::filter_type type = filter_info_base::DIGITAL_I16; +    boost::int16_t taps_array[] = {-9, 0, 73, 128, 73, 0, -9}; +    std::vector<boost::int16_t> taps(taps_array, taps_array + sizeof(taps_array) / sizeof(boost::int16_t) ); + +    digital_filter_base<boost::int16_t>::sptr hb_3 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_3(direction)); +    digital_filter_base<boost::int16_t>::sptr dec_int_3 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_dec_int_3(direction)); + +    if(direction == RX) +    { +        full_scale = 256; +        dec = 2; +        enable = _io_iface->peek8(0x003); +    } else { +        full_scale = 128; +        interpol = 2; +        enable = _io_iface->peek8(0x002); +    } + +    enable = ((enable >> 3) & 0x01); + +    if(!(hb_3->is_bypassed())) +    { +        if(direction == RX) +        { +            rate = hb_3->get_output_rate(); +        }else if (direction == TX) { +            rate = hb_3->get_input_rate(); +            if(enable) +            { +                rate /= 2; +            } +        } +    } else { //else dec3/int3 or none of them is used. +        if(direction == RX) +        { +            rate = dec_int_3->get_output_rate(); +        }else if (direction == TX) { +            rate = dec_int_3->get_input_rate(); +            if(enable) +            { +                rate /= 2; +            } +        } +    } + +    filter_info_base::sptr hb(new digital_filter_base<boost::int16_t>(type, (enable == 0) ? true : false, 3, rate, interpol, dec, full_scale, taps.size(), taps)); +    return  hb; +} + +filter_info_base::sptr ad9361_device_t::_get_filter_hb_1(direction_t direction) +{ +    boost::uint8_t enable = 0; +    double rate = 0; +    double full_scale = 0; +    size_t dec = 1; +    size_t interpol = 1; +    filter_info_base::filter_type type = filter_info_base::DIGITAL_I16; + +    std::vector<boost::int16_t> taps; +    boost::int16_t taps_rx_array[] = {-8, 0, 42, 0, -147, 0, 619, 1013, 619, 0, -147, 0, 42, 0, -8}; +    boost::int16_t taps_tx_array[] = {-53, 0, 313, 0, -1155, 0, 4989, 8192, 4989, 0, -1155, 0, 313, 0, -53}; + +    digital_filter_base<boost::int16_t>::sptr hb_2 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_2(direction)); + +    if(direction == RX) +    { +        full_scale = 2048; +        dec = 2; +        enable = _io_iface->peek8(0x003); +        enable = ((enable >> 2) & 0x01); +        rate = hb_2->get_output_rate(); +        taps.assign(taps_rx_array, taps_rx_array + sizeof(taps_rx_array) / sizeof(boost::int16_t) ); +    } else if (direction == TX) { +        full_scale = 8192; +        interpol = 2; +        enable = _io_iface->peek8(0x002); +        enable = ((enable >> 2) & 0x01); +        rate = hb_2->get_input_rate(); +        if(enable) +        { +            rate /= 2; +        } +        taps.assign(taps_tx_array, taps_tx_array + sizeof(taps_tx_array) / sizeof(boost::int16_t) ); +    } + +    filter_info_base::sptr hb(new digital_filter_base<boost::int16_t>(type, (enable == 0) ? true : false, 4, rate, interpol, dec, full_scale, taps.size(), taps)); +    return  hb; +} + +filter_info_base::sptr ad9361_device_t::_get_filter_fir(direction_t direction, chain_t chain) +{ +    double rate = 0; +    size_t dec = 1; +    size_t interpol = 1; +    size_t max_num_taps = 128; +    boost::uint8_t enable = 1; + +    digital_filter_base<boost::int16_t>::sptr hb_1 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_1(direction)); + +    if(direction == RX) +    { +        dec = _get_fir_dec_int(direction); +        if(dec == 0) +        { +            enable = 0; +            dec = 1; +        } +        interpol = 1; +        rate = hb_1->get_output_rate(); +    }else if (direction == TX) { +        interpol = _get_fir_dec_int(direction); +        if(interpol == 0) +        { +            enable = 0; +            interpol = 1; +        } +        dec = 1; +        rate = hb_1->get_input_rate(); +        if(enable) +        { +            rate /= interpol; +        } +    } +    max_num_taps = _get_num_fir_taps(direction); + +    filter_info_base::sptr fir(new digital_filter_fir<boost::int16_t>(filter_info_base::DIGITAL_FIR_I16, (enable == 0) ? true : false, 5, rate, interpol, dec, 32767, max_num_taps, _get_fir_taps(direction, chain))); + +    return fir; +} + +void ad9361_device_t::_set_filter_fir(direction_t direction, chain_t channel, filter_info_base::sptr filter) +{ +    digital_filter_fir<boost::int16_t>::sptr fir = boost::dynamic_pointer_cast<digital_filter_fir<boost::int16_t> >(filter); +    //only write taps. Ignore everything else for now +    _set_fir_taps(direction, channel, fir->get_taps()); +} + +/* + * If BW of one of the analog filters gets overwritten manually, + * _tx_analog_bw and _rx_analog_bw are not valid any more! + * For useful data in those variables set_bw_filter method should be used + */ +void ad9361_device_t::_set_filter_lp_bb(direction_t direction, filter_info_base::sptr filter) +{ +    analog_filter_lp::sptr lpf = boost::dynamic_pointer_cast<analog_filter_lp>(filter); +    double bw = lpf->get_cutoff(); +    if(direction == RX) +    { +        //remember: this function takes rf bw as its input and calibrated to 1.4 x the given value +        _rx_bb_lp_bw = _calibrate_baseband_rx_analog_filter(2 * bw / 1.4); //returns bb bw + +    } else { +        //remember: this function takes rf bw as its input and calibrates to 1.6 x the given value +        _tx_bb_lp_bw = _calibrate_baseband_tx_analog_filter(2 * bw / 1.6); +    } +} + +void ad9361_device_t::_set_filter_lp_tia_sec(direction_t direction, filter_info_base::sptr filter) +{ +    analog_filter_lp::sptr lpf = boost::dynamic_pointer_cast<analog_filter_lp>(filter); +    double bw = lpf->get_cutoff(); +    if(direction == RX) +    { +        //remember: this function takes rf bw as its input and calibrated to 2.5 x the given value +        _rx_tia_lp_bw = _calibrate_rx_TIAs(2 * bw / 2.5); //returns bb bw + +    } else { +        //remember: this function takes rf bw as its input and calibrates to 5 x the given value +        _tx_sec_lp_bw = _calibrate_secondary_tx_filter(2 * bw / 5); +    } +} +  }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 71ce78da7..a2038ea01 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -8,6 +8,14 @@  #include <ad9361_client.h>  #include <boost/noncopyable.hpp>  #include <boost/thread/recursive_mutex.hpp> +#include <uhd/types/filters.hpp> +#include <uhd/types/sensors.hpp> +#include <complex> +#include <vector> +#include <map> +#include "boost/assign.hpp" +#include "boost/bind.hpp" +#include "boost/function.hpp"  namespace uhd { namespace usrp { @@ -15,10 +23,41 @@ class ad9361_device_t : public boost::noncopyable  {  public:      enum direction_t { RX, TX }; -    enum chain_t { CHAIN_1, CHAIN_2 }; +    enum gain_mode_t {GAIN_MODE_MANUAL, GAIN_MODE_SLOW_AGC, GAIN_MODE_FAST_AGC}; +    enum chain_t { CHAIN_1, CHAIN_2, CHAIN_BOTH };      ad9361_device_t(ad9361_params::sptr client, ad9361_io::sptr io_iface) : -        _client_params(client), _io_iface(io_iface) {} +        _client_params(client), _io_iface(io_iface) { + +        /* +         * This Boost.Assign to_container() workaround is necessary because STL containers +         * apparently confuse newer versions of MSVC. +         * +         * Source: http://www.boost.org/doc/libs/1_55_0/libs/assign/doc/#portability +         */ + +        _rx_filters = (boost::assign::map_list_of("LPF_TIA", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_tia_sec, this, _1), +                                                    boost::bind(&ad9361_device_t::_set_filter_lp_tia_sec, this, _1, _3))) +                                            ("LPF_BB", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_bb, this, _1), +                                                    boost::bind(&ad9361_device_t::_set_filter_lp_bb, this, _1, _3))) +                                            ("HB_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_3, this, _1), 0)) +                                            ("DEC_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_dec_int_3, this, _1), 0)) +                                            ("HB_2", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_2, this, _1), 0)) +                                            ("HB_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_1, this, _1), 0)) +                                            ("FIR_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_fir, this, _1, _2), +                                                    boost::bind(&ad9361_device_t::_set_filter_fir, this, _1, _2, _3)))).to_container(_rx_filters); + +        _tx_filters = (boost::assign::map_list_of("LPF_SECONDARY", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_tia_sec, this, _1), +                                                    boost::bind(&ad9361_device_t::_set_filter_lp_tia_sec, this, _1, _3))) +                                            ("LPF_BB", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_bb, this, _1), +                                                    boost::bind(&ad9361_device_t::_set_filter_lp_bb, this, _1, _3))) +                                            ("HB_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_3, this, _1), 0)) +                                            ("INT_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_dec_int_3, this, _1), 0)) +                                            ("HB_2", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_2, this, _1), 0)) +                                            ("HB_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_1, this, _1), 0)) +                                            ("FIR_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_fir, this, _1, _2), +                                                    boost::bind(&ad9361_device_t::_set_filter_fir, this, _1, _2, _3)))).to_container(_tx_filters); +    }      /* Initialize the AD9361 codec. */      void initialize(); @@ -69,21 +108,56 @@ public:      /* Read back the internal RSSI measurement data. */      double get_rssi(chain_t chain); +    /*! Read the internal temperature sensor +     *\param calibrate return raw sensor readings or apply calibration factor. +     *\param num_samples number of measurements to average over +     */ +    double get_average_temperature(const double cal_offset = -30.0, const size_t num_samples = 3); + +    /* Turn on/off AD9361's RX DC offset correction */ +    void set_dc_offset_auto(direction_t direction, const bool on); + +    /* Turn on/off AD9361's RX IQ imbalance correction */ +    void set_iq_balance_auto(direction_t direction, const bool on); + +    /* Configure AD9361's AGC module to use either fast or slow AGC mode. */ +    void set_agc_mode(chain_t chain, gain_mode_t gain_mode); + +    /* Enable AD9361's AGC gain mode. */ +    void set_agc(chain_t chain, bool enable); + +    /* Set bandwidth of AD9361's analog LP filters. +     * Bandwidth should be RF bandwidth */ +    double set_bw_filter(direction_t direction, const double rf_bw); + +    /* +     * Filter API implementation +     * */ +    filter_info_base::sptr get_filter(direction_t direction, chain_t chain, const std::string &name); + +    void set_filter(direction_t direction, chain_t chain, const std::string &name, filter_info_base::sptr filter); + +    std::vector<std::string> get_filter_names(direction_t direction); +      //Constants      static const double AD9361_MAX_GAIN;      static const double AD9361_MAX_CLOCK_RATE; +    static const double AD9361_CAL_VALID_WINDOW;      static const double AD9361_RECOMMENDED_MAX_BANDWIDTH;  private:    //Methods      void _program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs);      void _setup_tx_fir(size_t num_taps, boost::int32_t interpolation);      void _setup_rx_fir(size_t num_taps, boost::int32_t decimation); +    void _program_fir_filter(direction_t direction, chain_t chain, int num_taps, boost::uint16_t *coeffs); +    void _setup_tx_fir(size_t num_taps); +    void _setup_rx_fir(size_t num_taps);      void _calibrate_lock_bbpll();      void _calibrate_synth_charge_pumps(); -    double _calibrate_baseband_rx_analog_filter(); -    double _calibrate_baseband_tx_analog_filter(); -    void _calibrate_secondary_tx_filter(); -    void _calibrate_rx_TIAs(); +    double _calibrate_baseband_rx_analog_filter(double rfbw); +    double _calibrate_baseband_tx_analog_filter(double rfbw); +    double _calibrate_secondary_tx_filter(double rfbw); +    double _calibrate_rx_TIAs(double rfbw);      void _setup_adc();      void _calibrate_baseband_dc_offset();      void _calibrate_rf_dc_offset(); @@ -92,12 +166,29 @@ private:    //Methods      void _calibrate_tx_quadrature();      void _program_mixer_gm_subtable();      void _program_gain_table(); -    void _setup_gain_control(); +    void _setup_gain_control(bool use_agc);      void _setup_synth(direction_t direction, double vcorate);      double _tune_bbvco(const double rate);      void _reprogram_gains();      double _tune_helper(direction_t direction, const double value);      double _setup_rates(const double rate); +    double _get_temperature(const double cal_offset, const double timeout = 0.1); +    void _configure_bb_rf_dc_tracking(const bool on); +    void _setup_agc(chain_t chain, gain_mode_t gain_mode); +    void _set_fir_taps(direction_t direction, chain_t chain, const std::vector<boost::int16_t>& taps); +    std::vector<boost::int16_t> _get_fir_taps(direction_t direction, chain_t chain); +    size_t _get_num_fir_taps(direction_t direction); +    size_t _get_fir_dec_int(direction_t direction); +    filter_info_base::sptr _get_filter_lp_tia_sec(direction_t direction); +    filter_info_base::sptr _get_filter_lp_bb(direction_t direction); +    filter_info_base::sptr _get_filter_dec_int_3(direction_t direction); +    filter_info_base::sptr _get_filter_hb_3(direction_t direction); +    filter_info_base::sptr _get_filter_hb_2(direction_t direction); +    filter_info_base::sptr _get_filter_hb_1(direction_t direction); +    filter_info_base::sptr _get_filter_fir(direction_t direction, chain_t chain); +    void _set_filter_fir(direction_t direction, chain_t channel, filter_info_base::sptr filter); +    void _set_filter_lp_bb(direction_t direction, filter_info_base::sptr filter); +    void _set_filter_lp_tia_sec(direction_t direction, filter_info_base::sptr filter);  private:    //Members      typedef struct { @@ -110,11 +201,30 @@ private:    //Members          boost::uint8_t bbftune_mode;      } chip_regs_t; +    struct filter_query_helper +    { +        filter_query_helper( +                boost::function<filter_info_base::sptr (direction_t, chain_t)> p_get, +                boost::function<void (direction_t, chain_t, filter_info_base::sptr)> p_set +                ) : get(p_get), set(p_set) {  } + +        filter_query_helper(){ } + +        boost::function<filter_info_base::sptr (direction_t, chain_t)> get; +        boost::function<void (direction_t, chain_t, filter_info_base::sptr)> set; +    }; + +    std::map<std::string, filter_query_helper> _rx_filters; +    std::map<std::string, filter_query_helper> _tx_filters; +      //Interfaces      ad9361_params::sptr _client_params;      ad9361_io::sptr     _io_iface;      //Intermediate state      double              _rx_freq, _tx_freq, _req_rx_freq, _req_tx_freq; +    double              _last_calibration_freq; +    double              _rx_analog_bw, _tx_analog_bw, _rx_bb_lp_bw, _tx_bb_lp_bw; +    double              _rx_tia_lp_bw, _tx_sec_lp_bw;      //! Current baseband sampling rate (this is the actual rate the device is      //  is running at)      double              _baseband_bw; @@ -129,10 +239,14 @@ private:    //Members      double              _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain;      boost::int32_t      _tfir_factor;      boost::int32_t      _rfir_factor; +    gain_mode_t         _rx1_agc_mode, _rx2_agc_mode; +    bool                _rx1_agc_enable, _rx2_agc_enable;      //Register soft-copies      chip_regs_t         _regs;      //Synchronization      boost::recursive_mutex  _mutex; +    bool _use_dc_offset_correction; +    bool _use_iq_balance_correction;  };  }}  //namespace diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h index 786029d6e..553655fa5 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h @@ -7,91 +7,91 @@  #include <boost/cstdint.hpp> -boost::uint8_t gain_table_sub_1300mhz[77][5] = { {0,0x00,0x00,0x20,1}, -    {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0}, -    {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0}, -    {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0}, -    {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0}, -    {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0}, -    {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0}, -    {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0}, -    {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0}, -    {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0}, -    {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x27,0x20,1}, -    {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0}, -    {34,0x04,0x2B,0x00,1}, {35,0x24,0x21,0x20,0}, {36,0x24,0x22,0x00,1}, -    {37,0x44,0x20,0x20,0}, {38,0x44,0x21,0x00,0}, {39,0x44,0x22,0x00,0}, -    {40,0x44,0x23,0x00,0}, {41,0x44,0x24,0x00,0}, {42,0x44,0x25,0x00,0}, -    {43,0x44,0x26,0x00,0}, {44,0x44,0x27,0x00,0}, {45,0x44,0x28,0x00,0}, -    {46,0x44,0x29,0x00,0}, {47,0x44,0x2A,0x00,0}, {48,0x44,0x2B,0x00,0}, -    {49,0x44,0x2C,0x00,0}, {50,0x44,0x2D,0x00,0}, {51,0x44,0x2E,0x00,0}, -    {52,0x44,0x2F,0x00,0}, {53,0x44,0x30,0x00,0}, {54,0x44,0x31,0x00,0}, -    {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, -    {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, -    {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, -    {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, -    {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, -    {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, -    {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, -    {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_sub_1300mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, +{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 }, +{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, +{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, +{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, +{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 }, +{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 }, +{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 }, +{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 }, +{ 0x04, 0x28, 0x20 }, { 0x04, 0x29, 0x00 }, { 0x04, 0x2A, 0x00 }, +{ 0x04, 0x2B, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 }, +{ 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, { 0x44, 0x22, 0x00 }, +{ 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, { 0x44, 0x25, 0x00 }, +{ 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, { 0x44, 0x28, 0x00 }, +{ 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, { 0x44, 0x2B, 0x00 }, +{ 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, { 0x44, 0x2E, 0x00 }, +{ 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, { 0x44, 0x31, 0x00 }, +{ 0x44, 0x32, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } }; -boost::uint8_t gain_table_1300mhz_to_4000mhz[77][5] = {   {0,0x00,0x00,0x20,1}, -    {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0}, -    {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0}, -    {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0}, -    {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0}, -    {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0}, -    {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0}, -    {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0}, -    {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0}, -    {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0}, -    {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x28,0x20,1}, -    {31,0x04,0x29,0x00,0}, {32,0x04,0x2A,0x00,0}, {33,0x04,0x2B,0x00,0}, -    {34,0x24,0x20,0x20,0}, {35,0x24,0x21,0x00,1}, {36,0x44,0x20,0x20,0}, -    {37,0x44,0x21,0x00,1}, {38,0x44,0x22,0x00,0}, {39,0x44,0x23,0x00,0}, -    {40,0x44,0x24,0x00,0}, {41,0x44,0x25,0x00,0}, {42,0x44,0x26,0x00,0}, -    {43,0x44,0x27,0x00,0}, {44,0x44,0x28,0x00,0}, {45,0x44,0x29,0x00,0}, -    {46,0x44,0x2A,0x00,0}, {47,0x44,0x2B,0x00,0}, {48,0x44,0x2C,0x00,0}, -    {49,0x44,0x2D,0x00,0}, {50,0x44,0x2E,0x00,0}, {51,0x44,0x2F,0x00,0}, -    {52,0x44,0x30,0x00,0}, {53,0x44,0x31,0x00,0}, {54,0x44,0x32,0x00,0}, -    {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, -    {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, -    {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, -    {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, -    {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, -    {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, -    {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, -    {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_1300mhz_to_4000mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, +{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 }, +{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, +{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, +{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, +{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 }, +{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 }, +{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 }, +{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 }, +{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 }, +{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x24, 0x21, 0x20 }, +{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, +{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, +{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, +{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, +{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, +{ 0x44, 0x2E, 0x00 }, { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, +{ 0x44, 0x31, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } }; -boost::uint8_t gain_table_4000mhz_to_6000mhz[77][5] = { {0,0x00,0x00,0x20,1}, -    {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x00,0x00,0}, -    {4,0x00,0x00,0x00,0}, {5,0x00,0x01,0x00,0}, {6,0x00,0x02,0x00,0}, -    {7,0x00,0x03,0x00,0}, {8,0x01,0x01,0x20,1}, {9,0x01,0x02,0x00,0}, -    {10,0x01,0x03,0x00,0}, {11,0x01,0x04,0x20,1}, {12,0x01,0x05,0x00,0}, -    {13,0x01,0x06,0x00,0}, {14,0x01,0x07,0x00,0}, {15,0x01,0x08,0x00,0}, -    {16,0x01,0x09,0x00,0}, {17,0x01,0x0A,0x00,0}, {18,0x01,0x0B,0x00,0}, -    {19,0x01,0x0C,0x00,0}, {20,0x02,0x08,0x20,1}, {21,0x02,0x09,0x00,0}, -    {22,0x02,0x0A,0x00,0}, {23,0x02,0x0B,0x20,1}, {24,0x02,0x0C,0x00,0}, -    {25,0x02,0x0D,0x00,0}, {26,0x02,0x0E,0x00,0}, {27,0x02,0x0F,0x00,0}, -    {28,0x02,0x2A,0x20,1}, {29,0x02,0x2B,0x00,0}, {30,0x04,0x27,0x20,1}, -    {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0}, -    {34,0x04,0x2B,0x00,0}, {35,0x04,0x2C,0x00,0}, {36,0x04,0x2D,0x00,0}, -    {37,0x24,0x20,0x20,1}, {38,0x24,0x21,0x00,0}, {39,0x24,0x22,0x00,0}, -    {40,0x44,0x20,0x20,1}, {41,0x44,0x21,0x00,0}, {42,0x44,0x22,0x00,0}, -    {43,0x44,0x23,0x00,0}, {44,0x44,0x24,0x00,0}, {45,0x44,0x25,0x00,0}, -    {46,0x44,0x26,0x00,0}, {47,0x44,0x27,0x00,0}, {48,0x44,0x28,0x00,0}, -    {49,0x44,0x29,0x00,0}, {50,0x44,0x2A,0x00,0}, {51,0x44,0x2B,0x00,0}, -    {52,0x44,0x2C,0x00,0}, {53,0x44,0x2D,0x00,0}, {54,0x44,0x2E,0x00,0}, -    {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, -    {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, -    {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, -    {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, -    {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, -    {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, -    {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, -    {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_4000mhz_to_6000mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00 }, +{ 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, { 0x01, 0x01, 0x20 }, +{ 0x01, 0x02, 0x00 }, { 0x01, 0x03, 0x00 }, { 0x01, 0x04, 0x20 }, +{ 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, { 0x01, 0x07, 0x00 }, +{ 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, { 0x01, 0x0A, 0x00 }, +{ 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, { 0x02, 0x08, 0x20 }, +{ 0x02, 0x09, 0x00 }, { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x20 }, +{ 0x02, 0x0C, 0x00 }, { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, +{ 0x02, 0x0F, 0x00 }, { 0x02, 0x2A, 0x20 }, { 0x02, 0x2B, 0x00 }, +{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 }, +{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x04, 0x2C, 0x00 }, +{ 0x04, 0x2D, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 }, +{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, +{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, +{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, +{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, +{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, +{ 0x44, 0x2E, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };  #endif /* INCLUDED_AD9361_GAIN_TABLES_HPP */ diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h index cb320e1f4..0475a5eb1 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h @@ -6,20 +6,20 @@  #define INCLUDED_AD9361_SYNTH_LUT_HPP -double vco_index[53] = {12605000000, 12245000000, 11906000000, 11588000000, -                        11288000000, 11007000000, 10742000000, 10492000000, -                        10258000000, 10036000000, 9827800000, 9631100000, -                        9445300000, 9269800000, 9103600000, 8946300000, -                        8797000000, 8655300000, 8520600000, 8392300000, -                        8269900000, 8153100000, 8041400000, 7934400000, -                        7831800000, 7733200000, 7638400000, 7547100000, -                        7459000000, 7374000000, 7291900000, 7212400000, -                        7135500000, 7061000000, 6988700000, 6918600000, -                        6850600000, 6784600000, 6720500000, 6658200000, -                        6597800000, 6539200000, 6482300000, 6427000000, -                        6373400000, 6321400000, 6270900000, 6222000000, -                        6174500000, 6128400000, 6083600000, 6040100000, -                        5997700000}; +double vco_index[53] = {12605000000.0, 12245000000.0, 11906000000.0, 11588000000.0, +                        11288000000.0, 11007000000.0, 10742000000.0, 10492000000.0, +                        10258000000.0, 10036000000.0, 9827800000.0, 9631100000.0, +                        9445300000.0, 9269800000.0, 9103600000.0, 8946300000.0, +                        8797000000.0, 8655300000.0, 8520600000.0, 8392300000.0, +                        8269900000.0, 8153100000.0, 8041400000.0, 7934400000.0, +                        7831800000.0, 7733200000.0, 7638400000.0, 7547100000.0, +                        7459000000.0, 7374000000.0, 7291900000.0, 7212400000.0, +                        7135500000.0, 7061000000.0, 6988700000.0, 6918600000.0, +                        6850600000.0, 6784600000.0, 6720500000.0, 6658200000.0, +                        6597800000.0, 6539200000.0, 6482300000.0, 6427000000.0, +                        6373400000.0, 6321400000.0, 6270900000.0, 6222000000.0, +                        6174500000.0, 6128400000.0, 6083600000.0, 6040100000.0, +                        5997700000.0};  int synth_cal_lut[53][12] = {   {10, 0, 4, 0, 15, 8, 8, 13, 4, 13, 15, 9},                                  {10, 0, 4, 0, 15, 8, 9, 13, 4, 13, 15, 9}, diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp index 164437f40..e22834fd9 100644 --- a/host/lib/usrp/cores/gpio_core_200.hpp +++ b/host/lib/usrp/cores/gpio_core_200.hpp @@ -1,5 +1,5 @@  // -// Copyright 2011,2014 Ettus Research LLC +// Copyright 2011,2014,2015 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,10 +20,34 @@  #include <uhd/config.hpp>  #include <uhd/usrp/dboard_iface.hpp> +#include <boost/assign.hpp>  #include <boost/cstdint.hpp>  #include <boost/utility.hpp>  #include <boost/shared_ptr.hpp>  #include <uhd/types/wb_iface.hpp> +#include <map> + +typedef enum { +    GPIO_CTRL, +    GPIO_DDR, +    GPIO_OUT, +    GPIO_ATR_0X, +    GPIO_ATR_RX, +    GPIO_ATR_TX, +    GPIO_ATR_XX +} gpio_attr_t; + +typedef std::map<gpio_attr_t,std::string> gpio_attr_map_t; +static const gpio_attr_map_t gpio_attr_map = +    boost::assign::map_list_of +        (GPIO_CTRL,   "CTRL") +        (GPIO_DDR,    "DDR") +        (GPIO_OUT,    "OUT") +        (GPIO_ATR_0X, "ATR_0X") +        (GPIO_ATR_RX, "ATR_RX") +        (GPIO_ATR_TX, "ATR_TX") +        (GPIO_ATR_XX, "ATR_XX") +;  class gpio_core_200 : boost::noncopyable{  public: diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp index f2bee47a9..3b56ae19a 100644 --- a/host/lib/usrp/dboard_eeprom.cpp +++ b/host/lib/usrp/dboard_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,2015 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 @@ -15,6 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include <uhd/types/byte_vector.hpp>  #include <uhd/usrp/dboard_eeprom.hpp>  #include <uhd/exception.hpp>  #include <uhd/utils/log.hpp> @@ -27,30 +28,6 @@  using namespace uhd;  using namespace uhd::usrp; -/*********************************************************************** - * Utility functions - **********************************************************************/ - -//! create a string from a byte vector, return empty if invalid ascii -static const std::string bytes_to_string(const byte_vector_t &bytes){ -    std::string out; -    BOOST_FOREACH(boost::uint8_t byte, bytes){ -        if (byte < 32 or byte > 127) return out; -        out += byte; -    } -    return out; -} - -//! create a byte vector from a string, null terminate unless max length -static const byte_vector_t string_to_bytes(const std::string &string, size_t max_length){ -    byte_vector_t bytes; -    for (size_t i = 0; i < std::min(string.size(), max_length); i++){ -        bytes.push_back(string[i]); -    } -    if (bytes.size() < max_length - 1) bytes.push_back('\0'); -    return bytes; -} -  ////////////////////////////////////////////////////////////////////////  // format of daughterboard EEPROM  // 00: 0xDB code for ``I'm a daughterboard'' diff --git a/host/lib/usrp/e300/e300_defaults.hpp b/host/lib/usrp/e300/e300_defaults.hpp index 89afcb256..41e8453c4 100644 --- a/host/lib/usrp/e300/e300_defaults.hpp +++ b/host/lib/usrp/e300/e300_defaults.hpp @@ -24,7 +24,7 @@ namespace uhd { namespace usrp { namespace e300 {  static const double DEFAULT_TICK_RATE       = 32e6;  static const double MAX_TICK_RATE           = 50e6; -static const double MIN_TICK_RATE           = 1e6; +static const double MIN_TICK_RATE           = 10e6;  static const double DEFAULT_TX_SAMP_RATE    = 1.0e6;  static const double DEFAULT_RX_SAMP_RATE    = 1.0e6; @@ -70,7 +70,7 @@ public:      digital_interface_delays_t get_digital_interface_timing() {          digital_interface_delays_t delays;          delays.rx_clk_delay = 0; -        delays.rx_data_delay = 0xF; +        delays.rx_data_delay = 0x8;          delays.tx_clk_delay = 0;          delays.tx_data_delay = 0xF;          return delays; diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp index eea4d7f63..fbbca329a 100644 --- a/host/lib/usrp/e300/e300_fpga_defs.hpp +++ b/host/lib/usrp/e300/e300_fpga_defs.hpp @@ -21,7 +21,7 @@ namespace uhd { namespace usrp { namespace e300 { namespace fpga {  static const size_t NUM_RADIOS = 2; -static const boost::uint32_t COMPAT_MAJOR = 8; +static const boost::uint32_t COMPAT_MAJOR = 9;  static const boost::uint32_t COMPAT_MINOR = 0;  }}}} // namespace diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 515fccc08..de2357100 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -473,15 +473,14 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)      // internal gpios      ////////////////////////////////////////////////////////////////////      gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); -    const std::vector<std::string> gpio_attrs = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX"); -    BOOST_FOREACH(const std::string &attr, gpio_attrs) +    BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)      { -        _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr) -            .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr, _1)) +        _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second) +            .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr.first, _1))              .set(0);      }      _tree->create<boost::uint8_t>(mb_path / "gpio" / "INT0" / "READBACK") -        .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio, "READBACK")); +        .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio));      //////////////////////////////////////////////////////////////////// @@ -587,32 +586,35 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)      boost::this_thread::sleep(boost::posix_time::seconds(1));  } -boost::uint8_t e300_impl::_get_internal_gpio( -    gpio_core_200::sptr gpio, -    const std::string &) +boost::uint8_t e300_impl::_get_internal_gpio(gpio_core_200::sptr gpio)  {      return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));  }  void e300_impl::_set_internal_gpio(      gpio_core_200::sptr gpio, -    const std::string &attr, +    const gpio_attr_t attr,      const boost::uint32_t value)  { -    if (attr == "CTRL") +    switch (attr) +    { +    case GPIO_CTRL:          return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); -    else if (attr == "DDR") +    case GPIO_DDR:          return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); -    else if (attr == "OUT") +    case GPIO_OUT:          return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); -    else if (attr == "ATR_0X") +    case GPIO_ATR_0X:          return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); -    else if (attr == "ATR_RX") +    case GPIO_ATR_RX:          return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); -    else if (attr == "ATR_TX") +    case GPIO_ATR_TX:          return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); -    else if (attr == "ATR_XX") +    case GPIO_ATR_XX:          return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); +    default: +        UHD_THROW_INVALID_CODE_PATH(); +    }  }  uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx) @@ -654,6 +656,17 @@ void e300_impl::_enforce_tick_rate_limits(                      % direction              ));          } +        // Minimum rate restriction due to MMCM used in capture interface to AD9361. +        // Xilinx Artix-7 FPGA MMCM minimum input frequency is 10 MHz. +        const double min_tick_rate = uhd::usrp::e300::MIN_TICK_RATE / ((chan_count <= 1) ? 1 : 2); +        if (tick_rate - min_tick_rate < 0.0) +        { +            throw uhd::value_error(boost::str( +                boost::format("current master clock rate (%.6f MHz) set below minimum possible master clock rate (%.6f MHz)") +                    % (tick_rate/1e6) +                    % (min_tick_rate/1e6) +            )); +        }      }  } @@ -1040,6 +1053,8 @@ void e300_impl::_setup_radio(const size_t dspno)          _tree->create<int>(rf_fe_path / "sensors"); //empty TODO          _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked")              .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, direction == "tx")); +        _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp") +            .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));          BOOST_FOREACH(const std::string &name, ad9361_ctrl::get_gain_names(key))          {              _tree->create<meta_range_t>(rf_fe_path / "gains" / name / "range") @@ -1065,6 +1080,18 @@ void e300_impl::_setup_radio(const size_t dspno)          _tree->create<meta_range_t>(rf_fe_path / "freq" / "range")              .publish(boost::bind(&ad9361_ctrl::get_rf_freq_range)); +        //only in local mode +        if(_xport_path == AXI) { +            //add all frontend filters +            std::vector<std::string> filter_names = _codec_ctrl->get_filter_names(key); +            for(size_t i = 0;i < filter_names.size(); i++) +            { +                _tree->create<filter_info_base::sptr>(rf_fe_path / "filters" / filter_names[i] / "value" ) +                    .publish(boost::bind(&ad9361_ctrl::get_filter, _codec_ctrl, key, filter_names[i])) +                    .subscribe(boost::bind(&ad9361_ctrl::set_filter, _codec_ctrl, key, filter_names[i], _1)); +            } +        } +          //setup RX related stuff          if (key[0] == 'R') {              static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2"); diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp index 7f83c16ed..c530a5d72 100644 --- a/host/lib/usrp/e300/e300_impl.hpp +++ b/host/lib/usrp/e300/e300_impl.hpp @@ -267,13 +267,11 @@ private: // methods      uhd::sensor_value_t _get_fe_pll_lock(const bool is_tx);      // internal gpios -    boost::uint8_t _get_internal_gpio( -        gpio_core_200::sptr, -        const std::string &); +    boost::uint8_t _get_internal_gpio(gpio_core_200::sptr);      void _set_internal_gpio(          gpio_core_200::sptr gpio, -        const std::string &attr, +        const gpio_attr_t attr,          const boost::uint32_t value);  private: // members diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp index 408f9e62d..d68dc4541 100644 --- a/host/lib/usrp/e300/e300_network.cpp +++ b/host/lib/usrp/e300/e300_network.cpp @@ -230,6 +230,27 @@ static void e300_codec_ctrl_tunnel(              case codec_xact_t::ACTION_GET_RSSI:                  out->rssi = _codec_ctrl->get_rssi(which_str).to_real();                  break; +            case codec_xact_t::ACTION_GET_TEMPERATURE: +                out->temp = _codec_ctrl->get_temperature().to_real(); +                break; +            case codec_xact_t::ACTION_SET_DC_OFFSET_AUTO: +                _codec_ctrl->set_dc_offset_auto(which_str, in->use_dc_correction == 1); +                break; +            case codec_xact_t::ACTION_SET_IQ_BALANCE_AUTO: +                _codec_ctrl->set_iq_balance_auto(which_str, in->use_iq_correction == 1); +            case codec_xact_t::ACTION_SET_AGC: +                _codec_ctrl->set_agc(which_str, in->use_agc == 1); +                break; +            case codec_xact_t::ACTION_SET_AGC_MODE: +                if(in->agc_mode == 0) { +                    _codec_ctrl->set_agc_mode(which_str, "slow"); +                } else if (in->agc_mode == 1) { +                    _codec_ctrl->set_agc_mode(which_str, "fast"); +                } +                break; +            case codec_xact_t::ACTION_SET_BW: +                out->bw = _codec_ctrl->set_bw_filter(which_str, in->bw); +                break;              default:                  UHD_MSG(status) << "Got unknown request?!" << std::endl;                  //Zero out actions to fail this request on client diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index 6742f5f86..9708634dd 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -130,10 +130,118 @@ public:          _args.bits = uhd::htonx<boost::uint32_t>(0);          _transact(); -          return sensor_value_t("RSSI", _retval.rssi, "dB");      } +    sensor_value_t get_temperature() +    { +        _clear(); +        _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_GET_TEMPERATURE); +        _args.which  = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_NONE);  /*Unused*/ +        _args.bits = uhd::htonx<boost::uint32_t>(0); + +        _transact(); +        return sensor_value_t("temp", _retval.temp, "C"); +    } + +    void set_dc_offset_auto(const std::string &which, const bool on) +    { +        _clear(); +        _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_DC_OFFSET_AUTO); +        if (which == "TX1")      _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); +        else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); +        else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); +        else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); +        else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); +        _args.use_dc_correction = on ? 1 : 0; + +        _transact(); +    } + +    void set_iq_balance_auto(const std::string &which, const bool on) +    { +        _clear(); +        _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_IQ_BALANCE_AUTO); +        if (which == "TX1")     _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); +        else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); +        else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); +        else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); +        else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); +        _args.use_iq_correction = on ? 1 : 0; + +        _transact(); +    } + +    void set_agc(const std::string &which, bool enable) +    { +        _clear(); +       _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC); +       if (which == "TX1")      _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); +       else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); +       else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); +       else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); +       else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); +       _args.use_agc = enable ? 1 : 0; + +       _transact(); +    } + +    void set_agc_mode(const std::string &which, const std::string &mode) +    { +        _clear(); +       _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC_MODE); + +       if (which == "TX1")      _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); +       else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); +       else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); +       else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); +       else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); + +       if(mode == "slow") { +           _args.agc_mode = 0; +       } else if (mode == "fast") { +           _args.agc_mode = 1; +       } else { +           throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect agc mode."); +       } + +       _transact(); +    } + +    //! set the filter bandwidth for the frontend's analog low pass +    double set_bw_filter(const std::string &which, const double bw) +    { +        _clear(); +        _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_BW); +        if (which == "TX1")      _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); +        else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); +        else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); +        else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); +        else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); +        _args.bw = bw; + +        _transact(); +        return _retval.bw; +    } + +    //! List all available filters by name +    std::vector<std::string> get_filter_names(const std::string &) +    { +        UHD_THROW_INVALID_CODE_PATH(); +    } + +    //! Return a list of all filters +    filter_info_base::sptr get_filter(const std::string &, const std::string &) +    { +        UHD_THROW_INVALID_CODE_PATH(); +    } + +    //! Write back a filter +    void set_filter(const std::string &, const std::string &, const filter_info_base::sptr) +    { +        UHD_THROW_INVALID_CODE_PATH(); +    } +  private:      void _transact() {          { diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp index e21f2ef95..43723e0d5 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp @@ -34,6 +34,12 @@ public:              double          gain;              double          freq;              double          rssi; +            double          temp; +            double          bw; +            boost::uint32_t use_dc_correction; +            boost::uint32_t use_iq_correction; +            boost::uint32_t use_agc; +            boost::uint32_t agc_mode;              boost::uint64_t bits;          }; @@ -44,7 +50,13 @@ public:          static const boost::uint32_t ACTION_TUNE                = 13;          static const boost::uint32_t ACTION_SET_LOOPBACK        = 14;          static const boost::uint32_t ACTION_GET_RSSI            = 15; -        static const boost::uint32_t ACTION_GET_FREQ            = 16; +        static const boost::uint32_t ACTION_GET_TEMPERATURE     = 16; +        static const boost::uint32_t ACTION_SET_DC_OFFSET_AUTO  = 17; +        static const boost::uint32_t ACTION_SET_IQ_BALANCE_AUTO = 18; +        static const boost::uint32_t ACTION_SET_AGC             = 19; +        static const boost::uint32_t ACTION_SET_AGC_MODE        = 20; +        static const boost::uint32_t ACTION_SET_BW              = 21; +        static const boost::uint32_t ACTION_GET_FREQ            = 22;          //Values for "which"          static const boost::uint32_t CHAIN_NONE = 0; diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index 68c084589..9c92fe252 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2013 Ettus Research LLC +// Copyright 2010-2013,2015 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,6 +16,7 @@  //  #include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/byte_vector.hpp>  #include <uhd/types/mac_addr.hpp>  #include <uhd/utils/byteswap.hpp>  #include <boost/asio/ip/address_v4.hpp> @@ -39,32 +40,6 @@ static const size_t NAME_MAX_LEN = 32 - SERIAL_LEN;   * Utility functions   **********************************************************************/ -//! A wrapper around std::copy that takes ranges instead of iterators. -template<typename RangeSrc, typename RangeDst> inline -void byte_copy(const RangeSrc &src, RangeDst &dst){ -    std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); -} - -//! create a string from a byte vector, return empty if invalid ascii -static const std::string bytes_to_string(const byte_vector_t &bytes){ -    std::string out; -    BOOST_FOREACH(boost::uint8_t byte, bytes){ -        if (byte < 32 or byte > 127) return out; -        out += byte; -    } -    return out; -} - -//! create a byte vector from a string, null terminate unless max length -static const byte_vector_t string_to_bytes(const std::string &string, size_t max_length){ -    byte_vector_t bytes; -    for (size_t i = 0; i < std::min(string.size(), max_length); i++){ -        bytes.push_back(string[i]); -    } -    if (bytes.size() < max_length - 1) bytes.push_back('\0'); -    return bytes; -} -  //! convert a string to a byte vector to write to eeprom  static byte_vector_t string_to_uint16_bytes(const std::string &num_str){      const boost::uint16_t num = boost::lexical_cast<boost::uint16_t>(num_str); diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 794438b90..1866255c9 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -30,6 +30,8 @@  #include <boost/thread.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp> +#include <boost/algorithm/string.hpp> +#include <algorithm>  #include <cmath>  using namespace uhd; @@ -431,6 +433,9 @@ public:       ******************************************************************/      void set_master_clock_rate(double rate, size_t mboard){          if (mboard != ALL_MBOARDS){ +            if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) { +                _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false); +            }              _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);              return;          } @@ -821,6 +826,26 @@ public:      }      void set_rx_gain(double gain, const std::string &name, size_t chan){ +        /* Check if any AGC mode is enable and if so warn the user */ +        if (chan != ALL_CHANS) { +            if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc")) { +                bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get(); +                if(agc) { +                    UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl; +                } +            } +        } else { +            for (size_t c = 0; c < get_rx_num_channels(); c++){ +                if (_tree->exists(rx_rf_fe_root(c) / "gain" / "agc")) { +                    bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get(); +                    if(agc) { +                        UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl; +                    } +                } +            } +        } +        /* Apply gain setting. +         * If device is in AGC mode it will ignore the setting. */          try {              return rx_gain_group(chan)->set_value(gain, name);          } catch (uhd::key_error &) { @@ -828,6 +853,32 @@ public:          }      } +    void set_normalized_rx_gain(double gain, size_t chan = 0) +    { +      if (gain > 1.0 || gain < 0.0) { +        throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); +      } +      gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); +      double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); +      set_rx_gain(abs_gain, ALL_GAINS, chan); +    } + +    void set_rx_agc(bool enable, size_t chan = 0) +    { +        if (chan != ALL_CHANS){ +            if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc" / "enable")) { +                _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").set(enable); +            } else { +                UHD_MSG(warning) << "AGC is not available on this device." << std::endl; +            } +            return; +        } +        for (size_t c = 0; c < get_rx_num_channels(); c++){ +            this->set_rx_agc(enable, c); +        } + +    } +      double get_rx_gain(const std::string &name, size_t chan){          try {              return rx_gain_group(chan)->get_value(name); @@ -836,6 +887,21 @@ public:          }      } +    double get_normalized_rx_gain(size_t chan) +    { +      gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); +      double gain_range_width = gain_range.stop() - gain_range.start(); +      // In case we have a device without a range of gains: +      if (gain_range_width == 0.0) { +          return 0; +      } +      double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; +      // Avoid rounding errors: +      if (norm_gain > 1.0) return 1.0; +      if (norm_gain < 0.0) return 0.0; +      return norm_gain; +    } +      gain_range_t get_rx_gain_range(const std::string &name, size_t chan){          try {              return rx_gain_group(chan)->get_range(name); @@ -888,6 +954,9 @@ public:          if (chan != ALL_CHANS){              if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) {                  _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb); +            } else if (_tree->exists(rx_rf_fe_root(chan) / "dc_offset" / "enable")) { +                /*For B2xx devices the dc-offset correction is implemented in the rf front-end*/ +                _tree->access<bool>(rx_rf_fe_root(chan) / "dc_offset" / "enable").set(enb);              } else {                  UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl;              } @@ -912,6 +981,20 @@ public:          }      } +    void set_rx_iq_balance(const bool enb, size_t chan){ +        if (chan != ALL_CHANS){ +            if (_tree->exists(rx_rf_fe_root(chan) / "iq_balance" / "enable")) { +                _tree->access<bool>(rx_rf_fe_root(chan) / "iq_balance" / "enable").set(enb); +            } else { +                UHD_MSG(warning) << "Setting IQ imbalance compensation is not possible on this device." << std::endl; +            } +            return; +        } +        for (size_t c = 0; c < get_rx_num_channels(); c++){ +            this->set_rx_iq_balance(enb, c); +        } +    } +      void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){          if (chan != ALL_CHANS){              if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) { @@ -926,6 +1009,87 @@ public:          }      } +    std::vector<std::string> get_filter_names(const std::string &search_mask) +    { +        std::vector<std::string> ret; + +        for (size_t chan = 0; chan < get_rx_num_channels(); chan++){ + +            if (_tree->exists(rx_rf_fe_root(chan) / "filters")) { +                std::vector<std::string> names = _tree->list(rx_rf_fe_root(chan) / "filters"); +                for(size_t i = 0; i < names.size(); i++) +                { +                    std::string name = rx_rf_fe_root(chan) / "filters" / names[i]; +                    if((search_mask.empty()) or boost::contains(name, search_mask)) { +                        ret.push_back(name); +                    } +                } +            } +            if (_tree->exists(rx_dsp_root(chan) / "filters")) { +                std::vector<std::string> names = _tree->list(rx_dsp_root(chan) / "filters"); +                for(size_t i = 0; i < names.size(); i++) +                { +                    std::string name = rx_dsp_root(chan) / "filters" / names[i]; +                    if((search_mask.empty()) or (boost::contains(name, search_mask))) { +                        ret.push_back(name); +                    } +                } +            } + +        } + +        for (size_t chan = 0; chan < get_tx_num_channels(); chan++){ + +            if (_tree->exists(tx_rf_fe_root(chan) / "filters")) { +                std::vector<std::string> names = _tree->list(tx_rf_fe_root(chan) / "filters"); +                for(size_t i = 0; i < names.size(); i++) +                { +                    std::string name = tx_rf_fe_root(chan) / "filters" / names[i]; +                    if((search_mask.empty()) or (boost::contains(name, search_mask))) { +                        ret.push_back(name); +                    } +                } +            } +            if (_tree->exists(rx_dsp_root(chan) / "filters")) { +                std::vector<std::string> names = _tree->list(tx_dsp_root(chan) / "filters"); +                for(size_t i = 0; i < names.size(); i++) +                { +                    std::string name = tx_dsp_root(chan) / "filters" / names[i]; +                    if((search_mask.empty()) or (boost::contains(name, search_mask))) { +                        ret.push_back(name); +                    } +                } +            } + +        } + +        return ret; +    } + +    filter_info_base::sptr get_filter(const std::string &path) +    { +        std::vector<std::string> possible_names = get_filter_names(""); +        std::vector<std::string>::iterator it; +        it = find(possible_names.begin(), possible_names.end(), path); +        if (it == possible_names.end()) { +            throw uhd::runtime_error("Attempting to get non-existing filter: "+path); +        } + +        return _tree->access<filter_info_base::sptr>(path / "value").get(); +    } + +    void set_filter(const std::string &path, filter_info_base::sptr filter) +    { +        std::vector<std::string> possible_names = get_filter_names(""); +        std::vector<std::string>::iterator it; +        it = find(possible_names.begin(), possible_names.end(), path); +        if (it == possible_names.end()) { +            throw uhd::runtime_error("Attempting to set non-existing filter: "+path); +        } + +        _tree->access<filter_info_base::sptr>(path / "value").set(filter); +    } +      /*******************************************************************       * TX methods       ******************************************************************/ @@ -1029,6 +1193,17 @@ public:          }      } +    void set_normalized_tx_gain(double gain, size_t chan = 0) +    { +      if (gain > 1.0 || gain < 0.0) { +        throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); +      } +      gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); +      double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); +      set_tx_gain(abs_gain, ALL_GAINS, chan); +    } + +      double get_tx_gain(const std::string &name, size_t chan){          try {              return tx_gain_group(chan)->get_value(name); @@ -1037,6 +1212,21 @@ public:          }      } +    double get_normalized_tx_gain(size_t chan) +    { +      gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); +      double gain_range_width = gain_range.stop() - gain_range.start(); +      // In case we have a device without a range of gains: +      if (gain_range_width == 0.0) { +          return 0.0; +      } +      double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; +      // Avoid rounding errors: +      if (norm_gain > 1.0) return 1.0; +      if (norm_gain < 0.0) return 0.0; +      return norm_gain; +    } +      gain_range_t get_tx_gain_range(const std::string &name, size_t chan){          try {              return tx_gain_group(chan)->get_range(name); diff --git a/host/lib/usrp/x300/x300_adc_ctrl.cpp b/host/lib/usrp/x300/x300_adc_ctrl.cpp index b0e4e4b95..edb4ce885 100644 --- a/host/lib/usrp/x300/x300_adc_ctrl.cpp +++ b/host/lib/usrp/x300/x300_adc_ctrl.cpp @@ -55,8 +55,8 @@ public:          _ads62p48_regs.lvds_cmos = ads62p48_regs_t::LVDS_CMOS_DDR_LVDS;          _ads62p48_regs.channel_control = ads62p48_regs_t::CHANNEL_CONTROL_INDEPENDENT;          _ads62p48_regs.data_format = ads62p48_regs_t::DATA_FORMAT_2S_COMPLIMENT; -        _ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_MINUS7_26; -        _ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_MINUS7_26; +        _ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_NORMAL; +        _ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_NORMAL;          this->send_ads62p48_reg(0); diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp index 6450686dd..0812bcc8e 100644 --- a/host/lib/usrp/x300/x300_clock_ctrl.cpp +++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp @@ -21,6 +21,7 @@  #include <uhd/utils/math.hpp>  #include <boost/cstdint.hpp>  #include <boost/format.hpp> +#include <boost/math/special_functions/round.hpp>  #include <stdexcept>  #include <cmath>  #include <cstdlib> @@ -29,6 +30,30 @@ static const double X300_REF_CLK_OUT_RATE  = 10e6;  static const boost::uint16_t X300_MAX_CLKOUT_DIV = 1045;  static const double X300_DEFAULT_DBOARD_CLK_RATE = 50e6; +struct x300_clk_delays { +    x300_clk_delays() : +        fpga_dly_ns(0.0),adc_dly_ns(0.0),dac_dly_ns(0.0),db_rx_dly_ns(0.0),db_tx_dly_ns(0.0) +    {} +    x300_clk_delays(double fpga, double adc, double dac, double db_rx, double db_tx) : +        fpga_dly_ns(fpga),adc_dly_ns(adc),dac_dly_ns(dac),db_rx_dly_ns(db_rx),db_tx_dly_ns(db_tx) +    {} + +    double fpga_dly_ns; +    double adc_dly_ns; +    double dac_dly_ns; +    double db_rx_dly_ns; +    double db_tx_dly_ns; +}; + +// Tune the FPGA->ADC clock delay to ensure a safe ADC_SSCLK -> RADIO_CLK crossing. +// If the FPGA_CLK is delayed, we also need to delay the reference clocks going to the DAC +// because the data interface clock is generated from FPGA_CLK. +static const x300_clk_delays X300_REV0_6_CLK_DELAYS = x300_clk_delays( +    /*fpga=*/0.000, /*adc=*/1.600, /*dac=*/0.000, /*db_rx=*/0.000, /*db_tx=*/0.000); + +static const x300_clk_delays X300_REV7_CLK_DELAYS = x300_clk_delays( +    /*fpga=*/0.000, /*adc=*/4.400, /*dac=*/0.000, /*db_rx=*/0.000, /*db_tx=*/0.000); +  using namespace uhd;  x300_clock_ctrl::~x300_clock_ctrl(void){ @@ -213,6 +238,187 @@ public:          _spiface->write_spi(_slaveno, spi_config_t::EDGE_RISE, data,32);      } +    double set_clock_delay(const x300_clock_which_t which, const double delay_ns, const bool resync = true) { +        //All dividers have are delayed by 5 taps by default. The delay +        //set by this function is relative to the 5 tap delay +        static const boost::uint16_t DDLY_MIN_TAPS  = 5; +        static const boost::uint16_t DDLY_MAX_TAPS  = 522;  //Extended mode + +        //The resolution and range of the analog delay is fixed +        static const double ADLY_RES_NS = 0.025; +        static const double ADLY_MIN_NS = 0.500; +        static const double ADLY_MAX_NS = 0.975; + +        //Each digital tap delays the clock by one VCO period +        double vco_period_ns = 1.0e9/_vco_freq; +        double half_vco_period_ns = vco_period_ns/2.0; + +        //Implement as much of the requested delay using digital taps. Whatever is leftover +        //will be made up using the analog delay element and the half-cycle digital tap. +        //A caveat here is that the analog delay starts at ADLY_MIN_NS, so we need to back off +        //by that much when coming up with the digital taps so that the difference can be made +        //up using the analog delay. +        boost::uint16_t ddly_taps = 0; +        if (delay_ns < ADLY_MIN_NS) { +            ddly_taps = static_cast<boost::uint16_t>(std::floor((delay_ns)/vco_period_ns)); +        } else { +            ddly_taps = static_cast<boost::uint16_t>(std::floor((delay_ns-ADLY_MIN_NS)/vco_period_ns)); +        } +        double leftover_delay = delay_ns - (vco_period_ns * ddly_taps); + +        //Compute settings +        boost::uint16_t ddly_value    = ddly_taps + DDLY_MIN_TAPS; +        bool            adly_en       = false; +        boost::uint8_t  adly_value    = 0; +        boost::uint8_t  half_shift_en = 0; + +        if (ddly_value > DDLY_MAX_TAPS) { +            throw uhd::value_error("set_clock_delay: Requested delay is out of range."); +        } + +        double coerced_delay = (vco_period_ns * ddly_taps); +        if (leftover_delay > ADLY_MAX_NS) { +            //The VCO is running too slowly for us to compensate the digital delay difference using +            //analog delay. Do the best we can. +            adly_en = true; +            adly_value = static_cast<boost::uint8_t>(boost::math::round((ADLY_MAX_NS-ADLY_MIN_NS)/ADLY_RES_NS)); +            coerced_delay += ADLY_MAX_NS; +        } else if (leftover_delay >= ADLY_MIN_NS && leftover_delay <= ADLY_MAX_NS) { +            //The leftover delay can be compensated by the analog delay up to the analog delay resolution +            adly_en = true; +            adly_value = static_cast<boost::uint8_t>(boost::math::round((leftover_delay-ADLY_MIN_NS)/ADLY_RES_NS)); +            coerced_delay += ADLY_MIN_NS+(ADLY_RES_NS*adly_value); +        } else if (leftover_delay >= (ADLY_MIN_NS - half_vco_period_ns) && leftover_delay < ADLY_MIN_NS) { +            //The leftover delay if less than the minimum supported analog delay but if we move the digital +            //delay back by half a VCO cycle then it will be in the range of the analog delay. So do that! +            adly_en = true; +            adly_value = static_cast<boost::uint8_t>(boost::math::round((leftover_delay+half_vco_period_ns-ADLY_MIN_NS)/ADLY_RES_NS)); +            half_shift_en = 1; +            coerced_delay += ADLY_MIN_NS+(ADLY_RES_NS*adly_value)-half_vco_period_ns; +        } else { +            //Even after moving the digital delay back by half a cycle, we cannot make up the difference +            //so give up on compensating for the difference from the digital delay tap. +            //If control reaches here then the value of leftover_delay is possible very small and will still +            //be close to what the client requested. +        } + +        UHD_LOGV(often) +            << boost::format("x300_clock_ctrl::set_clock_delay: Which=%d, Requested=%f, Digital Taps=%d, Half Shift=%d, Analog Delay=%d (%s), Coerced Delay=%fns" +            ) % which % delay_ns % ddly_value % (half_shift_en?"ON":"OFF") % ((int)adly_value) % (adly_en?"ON":"OFF") % coerced_delay << std::endl; + +        //Apply settings +        switch (which) +        { +        case X300_CLOCK_WHICH_FPGA: +            _lmk04816_regs.CLKout0_1_DDLY = ddly_value; +            _lmk04816_regs.CLKout0_1_HS = half_shift_en; +            if (adly_en) { +                _lmk04816_regs.CLKout0_ADLY_SEL = lmk04816_regs_t::CLKOUT0_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout1_ADLY_SEL = lmk04816_regs_t::CLKOUT1_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout0_1_ADLY = adly_value; +            } else { +                _lmk04816_regs.CLKout0_ADLY_SEL = lmk04816_regs_t::CLKOUT0_ADLY_SEL_D_PD; +                _lmk04816_regs.CLKout1_ADLY_SEL = lmk04816_regs_t::CLKOUT1_ADLY_SEL_D_PD; +            } +            write_regs(0); +            write_regs(6); +            _delays.fpga_dly_ns = coerced_delay; +            break; +        case X300_CLOCK_WHICH_DB0_RX: +        case X300_CLOCK_WHICH_DB1_RX: +            _lmk04816_regs.CLKout2_3_DDLY = ddly_value; +            _lmk04816_regs.CLKout2_3_HS = half_shift_en; +            if (adly_en) { +                _lmk04816_regs.CLKout2_ADLY_SEL = lmk04816_regs_t::CLKOUT2_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout3_ADLY_SEL = lmk04816_regs_t::CLKOUT3_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout2_3_ADLY = adly_value; +            } else { +                _lmk04816_regs.CLKout2_ADLY_SEL = lmk04816_regs_t::CLKOUT2_ADLY_SEL_D_PD; +                _lmk04816_regs.CLKout3_ADLY_SEL = lmk04816_regs_t::CLKOUT3_ADLY_SEL_D_PD; +            } +            write_regs(1); +            write_regs(6); +            _delays.db_rx_dly_ns = coerced_delay; +            break; +        case X300_CLOCK_WHICH_DB0_TX: +        case X300_CLOCK_WHICH_DB1_TX: +            _lmk04816_regs.CLKout4_5_DDLY = ddly_value; +            _lmk04816_regs.CLKout4_5_HS = half_shift_en; +            if (adly_en) { +                _lmk04816_regs.CLKout4_ADLY_SEL = lmk04816_regs_t::CLKOUT4_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout5_ADLY_SEL = lmk04816_regs_t::CLKOUT5_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout4_5_ADLY = adly_value; +            } else { +                _lmk04816_regs.CLKout4_ADLY_SEL = lmk04816_regs_t::CLKOUT4_ADLY_SEL_D_PD; +                _lmk04816_regs.CLKout5_ADLY_SEL = lmk04816_regs_t::CLKOUT5_ADLY_SEL_D_PD; +            } +            write_regs(2); +            write_regs(7); +            _delays.db_tx_dly_ns = coerced_delay; +            break; +        case X300_CLOCK_WHICH_DAC0: +        case X300_CLOCK_WHICH_DAC1: +            _lmk04816_regs.CLKout6_7_DDLY = ddly_value; +            _lmk04816_regs.CLKout6_7_HS = half_shift_en; +            if (adly_en) { +                _lmk04816_regs.CLKout6_ADLY_SEL = lmk04816_regs_t::CLKOUT6_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout7_ADLY_SEL = lmk04816_regs_t::CLKOUT7_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout6_7_ADLY = adly_value; +            } else { +                _lmk04816_regs.CLKout6_ADLY_SEL = lmk04816_regs_t::CLKOUT6_ADLY_SEL_D_PD; +                _lmk04816_regs.CLKout7_ADLY_SEL = lmk04816_regs_t::CLKOUT7_ADLY_SEL_D_PD; +            } +            write_regs(3); +            write_regs(7); +            _delays.dac_dly_ns = coerced_delay; +            break; +        case X300_CLOCK_WHICH_ADC0: +        case X300_CLOCK_WHICH_ADC1: +            _lmk04816_regs.CLKout8_9_DDLY = ddly_value; +            _lmk04816_regs.CLKout8_9_HS = half_shift_en; +            if (adly_en) { +                _lmk04816_regs.CLKout8_ADLY_SEL = lmk04816_regs_t::CLKOUT8_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout9_ADLY_SEL = lmk04816_regs_t::CLKOUT9_ADLY_SEL_D_BOTH; +                _lmk04816_regs.CLKout8_9_ADLY = adly_value; +            } else { +                _lmk04816_regs.CLKout8_ADLY_SEL = lmk04816_regs_t::CLKOUT8_ADLY_SEL_D_PD; +                _lmk04816_regs.CLKout9_ADLY_SEL = lmk04816_regs_t::CLKOUT9_ADLY_SEL_D_PD; +            } +            write_regs(4); +            write_regs(8); +            _delays.adc_dly_ns = coerced_delay; +            break; +        default: +            throw uhd::value_error("set_clock_delay: Requested source is invalid."); +        } + +        //Delays are applied only on a sync event +        if (resync) sync_clocks(); + +        return coerced_delay; +    } + +    double get_clock_delay(const x300_clock_which_t which) { +        switch (which) +        { +        case X300_CLOCK_WHICH_FPGA: +            return _delays.fpga_dly_ns; +        case X300_CLOCK_WHICH_DB0_RX: +        case X300_CLOCK_WHICH_DB1_RX: +            return _delays.db_rx_dly_ns; +        case X300_CLOCK_WHICH_DB0_TX: +        case X300_CLOCK_WHICH_DB1_TX: +            return _delays.db_tx_dly_ns; +        case X300_CLOCK_WHICH_DAC0: +        case X300_CLOCK_WHICH_DAC1: +            return _delays.dac_dly_ns; +        case X300_CLOCK_WHICH_ADC0: +        case X300_CLOCK_WHICH_ADC1: +            return _delays.adc_dly_ns; +        default: +            throw uhd::value_error("get_clock_delay: Requested source is invalid."); +        } +    }  private: @@ -409,7 +615,6 @@ private:          _lmk04816_regs.CLKout0_1_PD = lmk04816_regs_t::CLKOUT0_1_PD_POWER_UP;          this->write_regs(0);          _lmk04816_regs.CLKout0_1_DIV = master_clock_div; -        _lmk04816_regs.CLKout0_ADLY_SEL = lmk04816_regs_t::CLKOUT0_ADLY_SEL_D_EV_X;          this->write_regs(0);          // Register 1 @@ -433,9 +638,6 @@ private:          _lmk04816_regs.CLKout1_TYPE = lmk04816_regs_t::CLKOUT1_TYPE_P_DOWN; //CPRI feedback clock, use LVDS          _lmk04816_regs.CLKout2_TYPE = lmk04816_regs_t::CLKOUT2_TYPE_LVPECL_700MVPP; //DB_0_RX          _lmk04816_regs.CLKout3_TYPE = lmk04816_regs_t::CLKOUT3_TYPE_LVPECL_700MVPP; //DB_1_RX -        // Analog delay of 900ps to synchronize the radio clock with the source synchronous ADC clocks. -        // This delay may need to vary due to temperature.  Tested and verified at room temperature only. -        _lmk04816_regs.CLKout0_1_ADLY = 0x10;          // Register 7          _lmk04816_regs.CLKout4_TYPE = lmk04816_regs_t::CLKOUT4_TYPE_LVPECL_700MVPP; //DB_1_TX @@ -501,6 +703,19 @@ private:          // PLL2_P_30 set in individual cases above          // PLL2_N_30 set in individual cases above +        if (_hw_rev >= 7) { +            _delays = X300_REV7_CLK_DELAYS; +        } else { +            _delays = X300_REV0_6_CLK_DELAYS; +        } + +        //Apply delay values +        set_clock_delay(X300_CLOCK_WHICH_FPGA,   _delays.fpga_dly_ns,  false); +        set_clock_delay(X300_CLOCK_WHICH_DB0_RX, _delays.db_rx_dly_ns, false);  //Sets both Ch0 and Ch1 +        set_clock_delay(X300_CLOCK_WHICH_DB0_TX, _delays.db_tx_dly_ns, false);  //Sets both Ch0 and Ch1 +        set_clock_delay(X300_CLOCK_WHICH_ADC0,   _delays.adc_dly_ns,   false);  //Sets both Ch0 and Ch1 +        set_clock_delay(X300_CLOCK_WHICH_DAC0,   _delays.dac_dly_ns,   false);  //Sets both Ch0 and Ch1 +          /* Write the configuration values into the LMK */          for (size_t i = 1; i <= 16; ++i) {              this->write_regs(i); @@ -512,13 +727,14 @@ private:          this->sync_clocks();      } -    const spi_iface::sptr _spiface; -    const size_t _slaveno; -    const size_t _hw_rev; -    const double _master_clock_rate; -    const double _system_ref_rate; -    lmk04816_regs_t _lmk04816_regs; -    double _vco_freq; +    const spi_iface::sptr   _spiface; +    const size_t            _slaveno; +    const size_t            _hw_rev; +    const double            _master_clock_rate; +    const double            _system_ref_rate; +    lmk04816_regs_t         _lmk04816_regs; +    double                  _vco_freq; +    x300_clk_delays         _delays;  };  x300_clock_ctrl::sptr x300_clock_ctrl::make(uhd::spi_iface::sptr spiface, diff --git a/host/lib/usrp/x300/x300_clock_ctrl.hpp b/host/lib/usrp/x300/x300_clock_ctrl.hpp index 9c08aa356..160a14e6d 100644 --- a/host/lib/usrp/x300/x300_clock_ctrl.hpp +++ b/host/lib/usrp/x300/x300_clock_ctrl.hpp @@ -33,7 +33,7 @@ enum x300_clock_which_t      X300_CLOCK_WHICH_DB0_TX,      X300_CLOCK_WHICH_DB1_RX,      X300_CLOCK_WHICH_DB1_TX, -    X300_CLOCK_WHICH_TEST, +    X300_CLOCK_WHICH_FPGA,  };  class x300_clock_ctrl : boost::noncopyable @@ -94,6 +94,22 @@ public:       */      virtual void set_ref_out(const bool) = 0; +    /*! Set the clock delay for the given clock divider. +     * \param which which clock +     * \param rate the delay in nanoseconds +     * \param resync resync clocks to apply delays +     * \return the actual delay value set +     * \throw exception when which invalid or delay_ns out of range +     */ +    virtual double set_clock_delay(const x300_clock_which_t which, const double delay_ns, const bool resync = true) = 0; + +    /*! Get the clock delay for the given clock divider. +     * \param which which clock +     * \return the actual delay value set +     * \throw exception when which invalid +     */ +    virtual double get_clock_delay(const x300_clock_which_t which) = 0; +      /*! Reset the clocks.       *  Should be called if the reference clock changes       *  to reduce the time required to achieve a lock. diff --git a/host/lib/usrp/x300/x300_dac_ctrl.cpp b/host/lib/usrp/x300/x300_dac_ctrl.cpp index d3bcb8644..bb41146b6 100644 --- a/host/lib/usrp/x300/x300_dac_ctrl.cpp +++ b/host/lib/usrp/x300/x300_dac_ctrl.cpp @@ -129,12 +129,16 @@ public:          _check_pll();          // Configure digital interface settings -        write_ad9146_reg(0x16, 0x02); // Skew DCI signal by 615ps to find stable data eye -        write_ad9146_reg(0x03, 0x00); // 2's comp, I first, byte wide interface -        //fpga wants I,Q in the sample word: -        //first transaction goes into low bits -        //second transaction goes into high bits -        //therefore, we want Q to go first (bit 6 == 1) +        // Bypass DCI delay. We center the clock edge in the data +        // valid window in the FPGA by phase shifting the DCI going +        // to the DAC. +        write_ad9146_reg(0x16, 0x04); +        // 2's comp, I first, byte wide interface +        write_ad9146_reg(0x03, 0x00); +        // FPGA wants I,Q in the sample word: +        // - First transaction goes into low bits +        // - Second transaction goes into high bits +        //   therefore, we want Q to go first (bit 6 == 1)          write_ad9146_reg(0x03, (1 << 6)); //2s comp, i first, byte mode          // Configure interpolation filters diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 76531f921..175d37849 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -29,10 +29,10 @@  extern "C" {  #endif -#define X300_MAX_HW_REV 6 -#define X300_FW_COMPAT_MAJOR 3 +#define X300_MAX_HW_REV 7 +#define X300_FW_COMPAT_MAJOR 4  #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 9 +#define X300_FPGA_COMPAT_MAJOR 11  //shared memory sections - in between the stack and the program space  #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index aff150acb..91e6ded26 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 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,6 @@  //  #include "x300_impl.hpp" -#include "x300_regs.hpp"  #include "x300_lvbitx.hpp"  #include "x310_lvbitx.hpp"  #include <boost/algorithm/string.hpp> @@ -41,7 +40,7 @@  #define NIUSRPRIO_DEFAULT_RPC_PORT "5444" -#define X300_REV(x) (x - "A" + 1) +#define X300_REV(x) ((x) - "A" + 1)  using namespace uhd;  using namespace uhd::usrp; @@ -508,9 +507,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)          x300_load_fw(mb.zpu_ctrl, x300_fw_image);      } -    //check compat -- good place to do after conditional loading -    this->check_fw_compat(mb_path, mb.zpu_ctrl); +    //check compat numbers +    //check fpga compat before fw compat because the fw is a subset of the fpga image      this->check_fpga_compat(mb_path, mb.zpu_ctrl); +    this->check_fw_compat(mb_path, mb.zpu_ctrl);      //store which FPGA image is loaded      mb.loaded_fpga_image = get_fpga_option(mb.zpu_ctrl); @@ -696,23 +696,29 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      ////////////////////////////////////////////////////////////////////      // setup radios      //////////////////////////////////////////////////////////////////// -    UHD_MSG(status) << "Initialize Radio control..." << std::endl; -    this->setup_radio(mb_i, "A"); -    this->setup_radio(mb_i, "B"); +    this->setup_radio(mb_i, "A", dev_addr); +    this->setup_radio(mb_i, "B", dev_addr); + +    //////////////////////////////////////////////////////////////////// +    // ADC test and cal +    //////////////////////////////////////////////////////////////////// +    if (dev_addr.has_key("self_cal_adc_delay")) { +        self_cal_adc_xfer_delay(mb, true /* Apply ADC delay */); +    } +    self_test_adcs(mb);      ////////////////////////////////////////////////////////////////////      // front panel gpio      ////////////////////////////////////////////////////////////////////      mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); -    const std::vector<std::string> GPIO_ATTRS = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX"); -    BOOST_FOREACH(const std::string &attr, GPIO_ATTRS) +    BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)      { -        _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr) +        _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)              .set(0) -            .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr, _1)); +            .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr.first, _1));      }      _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK") -        .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio, "READBACK")); +        .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio));      ////////////////////////////////////////////////////////////////////      // register the time keepers - only one can be the highlander @@ -829,8 +835,15 @@ x300_impl::~x300_impl(void)      {          BOOST_FOREACH(mboard_members_t &mb, _mb)          { -            mb.radio_perifs[0].ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 2)); //disable/reset ADC/DAC -            mb.radio_perifs[1].ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 2)); //disable/reset ADC/DAC +            //disable/reset ADC/DAC +            mb.radio_perifs[0].misc_outs->set(radio_misc_outs_reg::ADC_RESET, 1); +            mb.radio_perifs[0].misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 0); +            mb.radio_perifs[0].misc_outs->set(radio_misc_outs_reg::DAC_ENABLED, 0); +            mb.radio_perifs[0].misc_outs->flush(); +            mb.radio_perifs[1].misc_outs->set(radio_misc_outs_reg::ADC_RESET, 1); +            mb.radio_perifs[1].misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 0); +            mb.radio_perifs[1].misc_outs->set(radio_misc_outs_reg::DAC_ENABLED, 0); +            mb.radio_perifs[1].misc_outs->flush();              //kill the claimer task and unclaim the device              mb.claimer_task.reset(); @@ -850,15 +863,7 @@ x300_impl::~x300_impl(void)      }  } -static void check_adc(wb_iface::sptr iface, const boost::uint32_t val) -{ -    boost::uint32_t adc_rb = iface->peek32(RB32_RX); -    adc_rb ^= 0xfffc0000; //adapt for I inversion in FPGA -    //UHD_MSG(status) << "adc_rb " << std::hex << adc_rb << "  val " << std::hex << val << std::endl; -    UHD_ASSERT_THROW(adc_rb == val); -} - -void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name) +void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, const uhd::device_addr_t &dev_addr)  {      const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_i);      UHD_ASSERT_THROW(mb_i < _mb.size()); @@ -866,6 +871,8 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name)      const size_t radio_index = mb.get_radio_index(slot_name);      radio_perifs_t &perif = mb.radio_perifs[radio_index]; +    UHD_MSG(status) << boost::format("Initialize Radio%d control...") % radio_index << std::endl; +      ////////////////////////////////////////////////////////////////////      // radio control      //////////////////////////////////////////////////////////////////// @@ -873,8 +880,20 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name)      boost::uint32_t ctrl_sid;      both_xports_t xport = this->make_transport(mb_i, dest, X300_RADIO_DEST_PREFIX_CTRL, device_addr_t(), ctrl_sid);      perif.ctrl = radio_ctrl_core_3000::make(mb.if_pkt_is_big_endian, xport.recv, xport.send, ctrl_sid, slot_name); -    perif.ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 2)); //reset adc + dac -    perif.ctrl->poke32(TOREG(SR_MISC_OUTS),  (1 << 1) | (1 << 0)); //out of reset + dac enable + +    perif.misc_outs = boost::make_shared<radio_misc_outs_reg>(); +    perif.misc_ins = boost::make_shared<radio_misc_ins_reg>(); +    perif.misc_outs->initialize(*perif.ctrl, true); +    perif.misc_ins->initialize(*perif.ctrl); + +    //reset adc + dac +    perif.misc_outs->set(radio_misc_outs_reg::ADC_RESET, 1); +    perif.misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 0); +    perif.misc_outs->flush(); +    perif.misc_outs->set(radio_misc_outs_reg::ADC_RESET, 0); +    perif.misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 1); +    perif.misc_outs->set(radio_misc_outs_reg::DAC_ENABLED, 1); +    perif.misc_outs->flush();      this->register_loopback_self_test(perif.ctrl); @@ -883,31 +902,16 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name)      perif.dac = x300_dac_ctrl::make(perif.spi, DB_DAC_SEN, mb.clock->get_master_clock_rate());      perif.leds = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_LEDS)); +    //Capture delays are calibrated every time. The status is only printed is the user +    //asks to run the xfer self cal using "self_cal_adc_delay" +    self_cal_adc_capture_delay(mb, radio_index, dev_addr.has_key("self_cal_adc_delay")); +      _tree->access<time_spec_t>(mb_path / "time" / "cmd")          .subscribe(boost::bind(&radio_ctrl_core_3000::set_time, perif.ctrl, _1));      _tree->access<double>(mb_path / "tick_rate")          .subscribe(boost::bind(&radio_ctrl_core_3000::set_tick_rate, perif.ctrl, _1));      //////////////////////////////////////////////////////////////// -    // ADC self test -    //////////////////////////////////////////////////////////////// -    perif.adc->set_test_word("ones", "ones"); check_adc(perif.ctrl, 0xfffcfffc); -    perif.adc->set_test_word("zeros", "zeros"); check_adc(perif.ctrl, 0x00000000); -    perif.adc->set_test_word("ones", "zeros"); check_adc(perif.ctrl, 0xfffc0000); -    perif.adc->set_test_word("zeros", "ones"); check_adc(perif.ctrl, 0x0000fffc); -    for (size_t k = 0; k < 14; k++) -    { -        perif.adc->set_test_word("zeros", "custom", 1 << k); -        check_adc(perif.ctrl, 1 << (k+2)); -    } -    for (size_t k = 0; k < 14; k++) -    { -        perif.adc->set_test_word("custom", "zeros", 1 << k); -        check_adc(perif.ctrl, 1 << (k+18)); -    } -    perif.adc->set_test_word("normal", "normal"); - -    ////////////////////////////////////////////////////////////////      // create codec control objects      ////////////////////////////////////////////////////////////////      _tree->create<int>(mb_path / "rx_codecs" / slot_name / "gains"); //phony property so this dir exists @@ -1442,8 +1446,8 @@ bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)          boost::this_thread::sleep(boost::posix_time::milliseconds(1));      } while (boost::get_system_time() < timeout_time); -    //failed to lock on reference -    return false; +    //Check one last time +    return get_ref_locked(ctrl).to_bool();  }  sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl) @@ -1544,20 +1548,24 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep   * front-panel GPIO   **********************************************************************/ -boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio, const std::string &) +boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio)  {      return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));  } -void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const std::string &attr, const boost::uint32_t value) +void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value)  { -    if (attr == "CTRL") return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); -    if (attr == "DDR") return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); -    if (attr == "OUT") return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); -    if (attr == "ATR_0X") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); -    if (attr == "ATR_RX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); -    if (attr == "ATR_TX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); -    if (attr == "ATR_XX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); +    switch (attr) +    { +    case GPIO_CTRL:   return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); +    case GPIO_DDR:    return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); +    case GPIO_OUT:    return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); +    case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); +    case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); +    case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); +    case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); +    default:        UHD_THROW_INVALID_CODE_PATH(); +    }  }  /*********************************************************************** @@ -1730,14 +1738,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_pcie(const std::string& res                  case X300_USRP_PCIE_SSID:                      mb_type = USRP_X300_MB; break;                  case X310_USRP_PCIE_SSID: -                case X310_2940R_PCIE_SSID: -                case X310_2942R_PCIE_SSID: -                case X310_2943R_PCIE_SSID: -                case X310_2944R_PCIE_SSID: -                case X310_2950R_PCIE_SSID: -                case X310_2952R_PCIE_SSID: -                case X310_2953R_PCIE_SSID: -                case X310_2954R_PCIE_SSID: +                case X310_2940R_40MHz_PCIE_SSID: +                case X310_2940R_120MHz_PCIE_SSID: +                case X310_2942R_40MHz_PCIE_SSID: +                case X310_2942R_120MHz_PCIE_SSID: +                case X310_2943R_40MHz_PCIE_SSID: +                case X310_2943R_120MHz_PCIE_SSID: +                case X310_2944R_40MHz_PCIE_SSID: +                case X310_2950R_40MHz_PCIE_SSID: +                case X310_2950R_120MHz_PCIE_SSID: +                case X310_2952R_40MHz_PCIE_SSID: +                case X310_2952R_120MHz_PCIE_SSID: +                case X310_2953R_40MHz_PCIE_SSID: +                case X310_2953R_120MHz_PCIE_SSID: +                case X310_2954R_40MHz_PCIE_SSID:                      mb_type = USRP_X310_MB; break;                  default:                      mb_type = UNKNOWN;      break; @@ -1765,14 +1779,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_eeprom(const uhd::usrp::mbo              case X300_USRP_PCIE_SSID:                  mb_type = USRP_X300_MB; break;              case X310_USRP_PCIE_SSID: -            case X310_2940R_PCIE_SSID: -            case X310_2942R_PCIE_SSID: -            case X310_2943R_PCIE_SSID: -            case X310_2944R_PCIE_SSID: -            case X310_2950R_PCIE_SSID: -            case X310_2952R_PCIE_SSID: -            case X310_2953R_PCIE_SSID: -            case X310_2954R_PCIE_SSID: +            case X310_2940R_40MHz_PCIE_SSID: +            case X310_2940R_120MHz_PCIE_SSID: +            case X310_2942R_40MHz_PCIE_SSID: +            case X310_2942R_120MHz_PCIE_SSID: +            case X310_2943R_40MHz_PCIE_SSID: +            case X310_2943R_120MHz_PCIE_SSID: +            case X310_2944R_40MHz_PCIE_SSID: +            case X310_2950R_40MHz_PCIE_SSID: +            case X310_2950R_120MHz_PCIE_SSID: +            case X310_2952R_40MHz_PCIE_SSID: +            case X310_2952R_120MHz_PCIE_SSID: +            case X310_2953R_40MHz_PCIE_SSID: +            case X310_2953R_120MHz_PCIE_SSID: +            case X310_2954R_40MHz_PCIE_SSID:                  mb_type = USRP_X310_MB; break;              default:                  UHD_MSG(warning) << "X300 unknown product code in EEPROM: " << product_num << std::endl; @@ -1782,3 +1802,288 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_eeprom(const uhd::usrp::mbo      return mb_type;  } +void x300_impl::self_cal_adc_capture_delay(mboard_members_t& mb, const size_t radio_i, bool print_status) +{ +    radio_perifs_t& perif = mb.radio_perifs[radio_i]; +    if (print_status) UHD_MSG(status) << "Running ADC capture delay self-cal..." << std::flush; + +    static const boost::uint32_t NUM_DELAY_STEPS = 32;   //The IDELAYE2 element has 32 steps +    static const boost::uint32_t NUM_RETRIES     = 2;    //Retry self-cal if it fails in warmup situations +    static const boost::int32_t  MIN_WINDOW_LEN  = 4; + +    boost::int32_t win_start = -1, win_stop = -1; +    boost::uint32_t iter = 0; +    while (iter++ < NUM_RETRIES) { +        for (boost::uint32_t dly_tap = 0; dly_tap < NUM_DELAY_STEPS; dly_tap++) { +            //Apply delay +            perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_VAL, dly_tap); +            perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_STB, 1); +            perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_STB, 0); + +            boost::uint32_t err_code = 0; + +            // -- Test I Channel -- +            //Put ADC in ramp test mode. Tie the other channel to all ones. +            perif.adc->set_test_word("ramp", "ones"); +            //Turn on the pattern checker in the FPGA. It will lock when it sees a zero +            //and count deviations from the expected value +            perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +            perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 1); +            //10ms @ 200MHz = 2 million samples +            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +            if (perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER0_I_LOCKED)) { +                err_code += perif.misc_ins->get(radio_misc_ins_reg::ADC_CHECKER0_I_ERROR); +            } else { +                err_code += 100;    //Increment error code by 100 to indicate no lock +            } + +            // -- Test Q Channel -- +            //Put ADC in ramp test mode. Tie the other channel to all ones. +            perif.adc->set_test_word("ones", "ramp"); +            //Turn on the pattern checker in the FPGA. It will lock when it sees a zero +            //and count deviations from the expected value +            perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +            perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 1); +            //10ms @ 200MHz = 2 million samples +            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +            if (perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER0_Q_LOCKED)) { +                err_code += perif.misc_ins->get(radio_misc_ins_reg::ADC_CHECKER0_Q_ERROR); +            } else { +                err_code += 100;    //Increment error code by 100 to indicate no lock +            } + +            if (err_code == 0) { +                if (win_start == -1) {      //This is the first window +                    win_start = dly_tap; +                    win_stop = dly_tap; +                } else {                    //We are extending the window +                    win_stop = dly_tap; +                } +            } else { +                if (win_start != -1) {      //A valid window turned invalid +                    if (win_stop - win_start >= MIN_WINDOW_LEN) { +                        break;              //Valid window found +                    } else { +                        win_start = -1;     //Reset window +                    } +                } +            } +            //UHD_MSG(status) << (boost::format("CapTap=%d, Error=%d\n") % dly_tap % err_code); +        } + +        //Retry the self-cal if it fails +        if ((win_start == -1 || (win_stop - win_start) < MIN_WINDOW_LEN) && iter < NUM_RETRIES /*not last iteration*/) { +            win_start = -1; +            win_stop = -1; +            boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); +        } else { +            break; +        } +    } +    perif.adc->set_test_word("normal", "normal"); +    perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); + +    if (win_start == -1) { +        throw uhd::runtime_error("self_cal_adc_capture_delay: Self calibration failed. Convergence error."); +    } + +    if (win_stop-win_start < MIN_WINDOW_LEN) { +        throw uhd::runtime_error("self_cal_adc_capture_delay: Self calibration failed. Valid window too narrow."); +    } + +    boost::uint32_t ideal_tap = (win_stop + win_start) / 2; +    perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_VAL, ideal_tap); +    perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_STB, 1); +    perif.misc_outs->write(radio_misc_outs_reg::ADC_DATA_DLY_STB, 0); + +    if (print_status) { +        double tap_delay = (1.0e12 / mb.clock->get_master_clock_rate()) / (2*32); //in ps +        UHD_MSG(status) << boost::format(" done (Tap=%d, Window=%d, TapDelay=%.3fps, Iter=%d)\n") % ideal_tap % (win_stop-win_start) % tap_delay % iter; +    } +} + +double x300_impl::self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay) +{ +    UHD_MSG(status) << "Running ADC transfer delay self-cal: " << std::flush; + +    //Effective resolution of the self-cal. +    static const size_t NUM_DELAY_STEPS = 100; + +    double master_clk_period = (1.0e9 / mb.clock->get_master_clock_rate()); //in ns +    double delay_start = 0.0; +    double delay_range = 2 * master_clk_period; +    double delay_incr = delay_range / NUM_DELAY_STEPS; + +    UHD_MSG(status) << "Measuring..." << std::flush; +    double cached_clk_delay = mb.clock->get_clock_delay(X300_CLOCK_WHICH_ADC0); +    double fpga_clk_delay = mb.clock->get_clock_delay(X300_CLOCK_WHICH_FPGA); + +    //Iterate through several values of delays and measure ADC data integrity +    std::vector< std::pair<double,bool> > results; +    for (size_t i = 0; i < NUM_DELAY_STEPS; i++) { +        //Delay the ADC clock (will set both Ch0 and Ch1 delays) +        double delay = mb.clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, delay_incr*i + delay_start); +        wait_for_ref_locked(mb.zpu_ctrl, 0.1); + +        boost::uint32_t err_code = 0; +        for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) { +            //Test each channel (I and Q) individually so as to not accidentally trigger +            //on the data from the other channel if there is a swap + +            // -- Test I Channel -- +            //Put ADC in ramp test mode. Tie the other channel to all ones. +            mb.radio_perifs[r].adc->set_test_word("ramp", "ones"); +            //Turn on the pattern checker in the FPGA. It will lock when it sees a zero +            //and count deviations from the expected value +            mb.radio_perifs[r].misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +            mb.radio_perifs[r].misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 1); +            //50ms @ 200MHz = 10 million samples +            boost::this_thread::sleep(boost::posix_time::milliseconds(50)); +            if (mb.radio_perifs[r].misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_I_LOCKED)) { +                err_code += mb.radio_perifs[r].misc_ins->get(radio_misc_ins_reg::ADC_CHECKER1_I_ERROR); +            } else { +                err_code += 100;    //Increment error code by 100 to indicate no lock +            } + +            // -- Test Q Channel -- +            //Put ADC in ramp test mode. Tie the other channel to all ones. +            mb.radio_perifs[r].adc->set_test_word("ones", "ramp"); +            //Turn on the pattern checker in the FPGA. It will lock when it sees a zero +            //and count deviations from the expected value +            mb.radio_perifs[r].misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +            mb.radio_perifs[r].misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 1); +            //50ms @ 200MHz = 10 million samples +            boost::this_thread::sleep(boost::posix_time::milliseconds(50)); +            if (mb.radio_perifs[r].misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_Q_LOCKED)) { +                err_code += mb.radio_perifs[r].misc_ins->get(radio_misc_ins_reg::ADC_CHECKER1_Q_ERROR); +            } else { +                err_code += 100;    //Increment error code by 100 to indicate no lock +            } +        } +        //UHD_MSG(status) << (boost::format("XferDelay=%fns, Error=%d\n") % delay % err_code); +        results.push_back(std::pair<double,bool>(delay, err_code==0)); +    } + +    //Calculate the valid window +    int win_start_idx = -1, win_stop_idx = -1, cur_start_idx = -1, cur_stop_idx = -1; +    for (size_t i = 0; i < results.size(); i++) { +        std::pair<double,bool>& item = results[i]; +        if (item.second) {  //If data is stable +            if (cur_start_idx == -1) {  //This is the first window +                cur_start_idx = i; +                cur_stop_idx = i; +            } else {                    //We are extending the window +                cur_stop_idx = i; +            } +        } else { +            if (cur_start_idx == -1) {  //We haven't yet seen valid data +                //Do nothing +            } else if (win_start_idx == -1) {   //We passed the first valid window +                win_start_idx = cur_start_idx; +                win_stop_idx = cur_stop_idx; +            } else {                    //Update cached window if current window is larger +                double cur_win_len = results[cur_stop_idx].first - results[cur_start_idx].first; +                double cached_win_len = results[win_stop_idx].first - results[win_start_idx].first; +                if (cur_win_len > cached_win_len) { +                    win_start_idx = cur_start_idx; +                    win_stop_idx = cur_stop_idx; +                } +            } +            //Reset current window +            cur_start_idx = -1; +            cur_stop_idx = -1; +        } +    } +    if (win_start_idx == -1) { +        throw uhd::runtime_error("self_cal_adc_xfer_delay: Self calibration failed. Convergence error."); +    } + +    double win_center = (results[win_stop_idx].first + results[win_start_idx].first) / 2.0; +    double win_length = results[win_stop_idx].first - results[win_start_idx].first; +    if (win_length < master_clk_period/4) { +        throw uhd::runtime_error("self_cal_adc_xfer_delay: Self calibration failed. Valid window too narrow."); +    } + +    //Cycle slip the relative delay by a clock cycle to prevent sample misalignment +    //fpga_clk_delay > 0 and 0 < win_center < 2*(1/MCR) so one cycle slip is all we need +    bool cycle_slip = (win_center-fpga_clk_delay >= master_clk_period); +    if (cycle_slip) { +        win_center -= master_clk_period; +    } + +    if (apply_delay) { +        UHD_MSG(status) << "Validating..." << std::flush; +        //Apply delay +        win_center = mb.clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, win_center);  //Sets ADC0 and ADC1 +        wait_for_ref_locked(mb.zpu_ctrl, 0.1); +        //Validate +        self_test_adcs(mb, 2000); +    } else { +        //Restore delay +        mb.clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, cached_clk_delay);  //Sets ADC0 and ADC1 +    } + +    //Teardown +    for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) { +        mb.radio_perifs[r].adc->set_test_word("normal", "normal"); +        mb.radio_perifs[r].misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +    } +    UHD_MSG(status) << (boost::format(" done (FPGA->ADC=%.3fns%s, Window=%.3fns)\n") % +        (win_center-fpga_clk_delay) % (cycle_slip?" +cyc":"") % win_length); + +    return win_center; +} + +static void check_adc(wb_iface::sptr iface, const boost::uint32_t val, const boost::uint32_t i) +{ +    boost::uint32_t adc_rb = iface->peek32(RB32_RX); +    adc_rb ^= 0xfffc0000; //adapt for I inversion in FPGA +    if (val != adc_rb) { +        throw uhd::runtime_error( +            (boost::format("ADC self-test failed for Radio%d. (Exp=0x%x, Got=0x%x)")%i%val%adc_rb).str()); +    } +} + +void x300_impl::self_test_adcs(mboard_members_t& mb, boost::uint32_t ramp_time_ms) { +    for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) { +        radio_perifs_t &perif = mb.radio_perifs[r]; + +        //First test basic patterns +        perif.adc->set_test_word("ones", "ones"); check_adc(perif.ctrl, 0xfffcfffc,r); +        perif.adc->set_test_word("zeros", "zeros"); check_adc(perif.ctrl, 0x00000000,r); +        perif.adc->set_test_word("ones", "zeros"); check_adc(perif.ctrl, 0xfffc0000,r); +        perif.adc->set_test_word("zeros", "ones"); check_adc(perif.ctrl, 0x0000fffc,r); +        for (size_t k = 0; k < 14; k++) +        { +            perif.adc->set_test_word("zeros", "custom", 1 << k); +            check_adc(perif.ctrl, 1 << (k+2),r); +        } +        for (size_t k = 0; k < 14; k++) +        { +            perif.adc->set_test_word("custom", "zeros", 1 << k); +            check_adc(perif.ctrl, 1 << (k+18),r); +        } + +        //Turn on ramp pattern test +        perif.adc->set_test_word("ramp", "ramp"); +        perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 0); +        perif.misc_outs->write(radio_misc_outs_reg::ADC_CHECKER_ENABLED, 1); +    } +    boost::this_thread::sleep(boost::posix_time::milliseconds(ramp_time_ms)); +    for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) { +        radio_perifs_t &perif = mb.radio_perifs[r]; + +        if (!perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_I_LOCKED) || +            perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_I_ERROR) || +            !perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_Q_LOCKED) || +            perif.misc_ins->read(radio_misc_ins_reg::ADC_CHECKER1_Q_ERROR)) +        { +            throw uhd::runtime_error( +                (boost::format("ADC self-test failed for Radio%d. (Ramp checker failure)")%r).str()); +        } + +        //Return to normal mode +        perif.adc->set_test_word("normal", "normal"); +    } +} + diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 890ef7bcb..dca6360b8 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 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 @@ -49,6 +49,8 @@  #include <uhd/transport/nirio/niusrprio_session.h>  #include <uhd/transport/vrt_if_packet.hpp>  #include "recv_packet_demuxer_3000.hpp" +#include <uhd/utils/soft_register.hpp> +#include "x300_regs.hpp"  static const std::string X300_FW_FILE_NAME  = "usrp_x300_fw.bin"; @@ -169,9 +171,43 @@ public:  private:      boost::shared_ptr<async_md_type> _async_md; +    class radio_misc_outs_reg : public uhd::soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(DAC_ENABLED,          /*width*/ 1, /*shift*/ 0);  //[0] +        UHD_DEFINE_SOFT_REG_FIELD(DAC_RESET_N,          /*width*/ 1, /*shift*/ 1);  //[1] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_RESET,            /*width*/ 1, /*shift*/ 2);  //[2] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_STB,     /*width*/ 1, /*shift*/ 3);  //[3] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL,     /*width*/ 5, /*shift*/ 4);  //[8:4] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER_ENABLED,  /*width*/ 1, /*shift*/ 9);  //[9] + +        radio_misc_outs_reg(): uhd::soft_reg32_wo_t(TOREG(SR_MISC_OUTS)) { +            //Initial values +            set(DAC_ENABLED, 0); +            set(DAC_RESET_N, 0); +            set(ADC_RESET, 0); +            set(ADC_DATA_DLY_STB, 0); +            set(ADC_DATA_DLY_VAL, 16); +            set(ADC_CHECKER_ENABLED, 0); +        } +    }; +    class radio_misc_ins_reg : public uhd::soft_reg32_ro_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER0_Q_LOCKED, /*width*/ 1, /*shift*/ 0);  //[0] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER0_I_LOCKED, /*width*/ 1, /*shift*/ 1);  //[1] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_Q_LOCKED, /*width*/ 1, /*shift*/ 2);  //[2] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_I_LOCKED, /*width*/ 1, /*shift*/ 3);  //[3] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER0_Q_ERROR,  /*width*/ 1, /*shift*/ 4);  //[4] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER0_I_ERROR,  /*width*/ 1, /*shift*/ 5);  //[5] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_Q_ERROR,  /*width*/ 1, /*shift*/ 6);  //[6] +        UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_I_ERROR,  /*width*/ 1, /*shift*/ 7);  //[7] + +        radio_misc_ins_reg(): uhd::soft_reg32_ro_t(RB32_MISC_INS) { } +    }; +      //perifs in the radio core      struct radio_perifs_t      { +        //Interfaces          radio_ctrl_core_3000::sptr ctrl;          spi_core_3000::sptr spi;          x300_adc_ctrl::sptr adc; @@ -184,6 +220,9 @@ private:          gpio_core_200_32wo::sptr leds;          rx_frontend_core_200::sptr rx_fe;          tx_frontend_core_200::sptr tx_fe; +        //Registers +        radio_misc_outs_reg::sptr misc_outs; +        radio_misc_ins_reg::sptr misc_ins;      };      //overflow recovery impl @@ -211,7 +250,8 @@ private:          i2c_core_100_wb32::sptr zpu_i2c;          //perifs in each radio -        radio_perifs_t radio_perifs[2]; //!< This is hardcoded s.t. radio_perifs[0] points to slot A and [1] to B +        static const size_t NUM_RADIOS = 2; +        radio_perifs_t radio_perifs[NUM_RADIOS]; //!< This is hardcoded s.t. radio_perifs[0] points to slot A and [1] to B          uhd::usrp::dboard_eeprom_t db_eeproms[8];          //! Return the index of a radio component, given a slot name. This means DSPs, radio_perifs          size_t get_radio_index(const std::string &slot_name) { @@ -259,7 +299,7 @@ private:        * \param mb_i Motherboard index        * \param slot_name Slot name (A or B).        */ -    void setup_radio(const size_t, const std::string &slot_name); +    void setup_radio(const size_t, const std::string &slot_name, const uhd::device_addr_t &dev_addr);      size_t _sid_framer;      struct sid_config_t @@ -361,8 +401,12 @@ private:      void check_fpga_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);      void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant); -    boost::uint32_t get_fp_gpio(gpio_core_200::sptr, const std::string &); -    void set_fp_gpio(gpio_core_200::sptr, const std::string &, const boost::uint32_t); +    boost::uint32_t get_fp_gpio(gpio_core_200::sptr); +    void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t); + +    void self_cal_adc_capture_delay(mboard_members_t& mb, const size_t radio_i, bool print_status = false); +    double self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay = false); +    void self_test_adcs(mboard_members_t& mb, boost::uint32_t ramp_time_ms = 100);      //**PRECONDITION**      //This function assumes that all the VITA times in "radios" are synchronized diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index 334ae8168..e3515af0c 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -23,6 +23,7 @@  #include <uhd/transport/nirio_zero_copy.hpp>  #include "async_packet_handler.hpp"  #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/chdr.hpp>  #include <boost/bind.hpp>  #include <uhd/utils/tasks.hpp>  #include <uhd/utils/log.hpp> @@ -124,41 +125,6 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i,  /*********************************************************************** - * VITA stuff - **********************************************************************/ -static void x300_if_hdr_unpack_be( -    const boost::uint32_t *packet_buff, -    vrt::if_packet_info_t &if_packet_info -){ -    if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; -    return vrt::if_hdr_unpack_be(packet_buff, if_packet_info); -} - -static void x300_if_hdr_pack_be( -    boost::uint32_t *packet_buff, -    vrt::if_packet_info_t &if_packet_info -){ -    if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; -    return vrt::if_hdr_pack_be(packet_buff, if_packet_info); -} - -static void x300_if_hdr_unpack_le( -    const boost::uint32_t *packet_buff, -    vrt::if_packet_info_t &if_packet_info -){ -    if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; -    return vrt::if_hdr_unpack_le(packet_buff, if_packet_info); -} - -static void x300_if_hdr_pack_le( -    boost::uint32_t *packet_buff, -    vrt::if_packet_info_t &if_packet_info -){ -    if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; -    return vrt::if_hdr_pack_le(packet_buff, if_packet_info); -} - -/***********************************************************************   * RX flow control handler   **********************************************************************/  static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, const device_addr_t& rx_args) @@ -209,9 +175,9 @@ static void handle_rx_flowctrl(const boost::uint32_t sid, zero_copy_if::sptr xpo      //load header      if (big_endian) -        x300_if_hdr_pack_be(pkt, packet_info); +        vrt::chdr::if_hdr_pack_be(pkt, packet_info);      else -        x300_if_hdr_pack_le(pkt, packet_info); +        vrt::chdr::if_hdr_pack_le(pkt, packet_info);      //load payload      pkt[packet_info.num_header_words32+0] = uhd::htonx<boost::uint32_t>(0); @@ -276,12 +242,12 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero      {          if (big_endian)          { -            x300_if_hdr_unpack_be(packet_buff, if_packet_info); +            vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info);              endian_conv = uhd::ntohx;          }          else          { -            x300_if_hdr_unpack_le(packet_buff, if_packet_info); +            vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info);              endian_conv = uhd::wtohx;          }      } @@ -430,10 +396,10 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)          //init some streamer stuff          std::string conv_endianness;          if (mb.if_pkt_is_big_endian) { -            my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_be); +            my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be);              conv_endianness = "be";          } else { -            my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_le); +            my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le);              conv_endianness = "le";          } @@ -594,10 +560,10 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)          std::string conv_endianness;          if (mb.if_pkt_is_big_endian) { -            my_streamer->set_vrt_packer(&x300_if_hdr_pack_be); +            my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be);              conv_endianness = "be";          } else { -            my_streamer->set_vrt_packer(&x300_if_hdr_pack_le); +            my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le);              conv_endianness = "le";          } diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index f920b5ae2..e984eb908 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -25,40 +25,41 @@  #define localparam static const int -localparam SR_DACSYNC   = 5; -localparam SR_LOOPBACK  = 6; -localparam SR_TEST      = 7; -localparam SR_SPI       = 8; -localparam SR_GPIO      = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK  = 32; -localparam SR_TX_CTRL   = 64; -localparam SR_RX_CTRL   = 96; -localparam SR_TIME      = 128; -localparam SR_RX_DSP    = 144; -localparam SR_TX_DSP    = 184; -localparam SR_LEDS      = 195; -localparam SR_FP_GPIO   = 200; -localparam SR_RX_FRONT  = 208; -localparam SR_TX_FRONT  = 216; - -localparam RB32_GPIO            = 0; -localparam RB32_SPI             = 4; -localparam RB64_TIME_NOW        = 8; -localparam RB64_TIME_PPS        = 16; -localparam RB32_TEST            = 24; -localparam RB32_RX              = 28; -localparam RB32_FP_GPIO         = 32; - -localparam BL_ADDRESS     = 0; -localparam BL_DATA        = 1; +localparam SR_DACSYNC    = 5; +localparam SR_LOOPBACK   = 6; +localparam SR_TEST       = 7; +localparam SR_SPI        = 8; +localparam SR_GPIO       = 16; +localparam SR_MISC_OUTS  = 24; +localparam SR_READBACK   = 32; +localparam SR_TX_CTRL    = 64; +localparam SR_RX_CTRL    = 96; +localparam SR_TIME       = 128; +localparam SR_RX_DSP     = 144; +localparam SR_TX_DSP     = 184; +localparam SR_LEDS       = 195; +localparam SR_FP_GPIO    = 200; +localparam SR_RX_FRONT   = 208; +localparam SR_TX_FRONT   = 216; + +localparam RB32_GPIO     = 0; +localparam RB32_SPI      = 4; +localparam RB64_TIME_NOW = 8; +localparam RB64_TIME_PPS = 16; +localparam RB32_TEST     = 24; +localparam RB32_RX       = 28; +localparam RB32_FP_GPIO  = 32; +localparam RB32_MISC_INS = 36; + +localparam BL_ADDRESS    = 0; +localparam BL_DATA       = 1;  //wishbone settings map - relevant to host code -#define SET0_BASE 0xa000 -#define SETXB_BASE 0xb000 -#define BOOT_LDR_BASE 0xFA00 -#define I2C0_BASE 0xfe00 -#define I2C1_BASE 0xff00 +#define SET0_BASE     0xa000 +#define SETXB_BASE    0xb000 +#define BOOT_LDR_BASE 0xfa00 +#define I2C0_BASE     0xfe00 +#define I2C1_BASE     0xff00  #define SR_ADDR(base, offset) ((base) + (offset)*4)  localparam ZPU_SR_LEDS       = 00; @@ -70,56 +71,62 @@ localparam ZPU_SR_ETHINT0    = 40;  localparam ZPU_SR_ETHINT1    = 56;  //clock controls -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL  0x00 -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL  0x02 -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO     0x03 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL  0x00 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL  0x02 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO     0x03 - -localparam ZPU_RB_SPI = 2; +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO    0x03 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO    0x03 + +localparam ZPU_RB_SPI        = 2;  localparam ZPU_RB_CLK_STATUS = 3;  localparam ZPU_RB_COMPAT_NUM = 6;  localparam ZPU_RB_ETH_TYPE0  = 4;  localparam ZPU_RB_ETH_TYPE1  = 5;  //clock status -#define ZPU_RB_CLK_STATUS_LMK_STATUS    (0x3 << 0) -#define ZPU_RB_CLK_STATUS_LMK_LOCK      (0x1 << 2) -#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER  (0x1 << 3) -#define ZPU_RB_CLK_STATUS_PPS_DETECT    (0x1 << 4) +#define ZPU_RB_CLK_STATUS_LMK_STATUS   (0x3 << 0) +#define ZPU_RB_CLK_STATUS_LMK_LOCK     (0x1 << 2) +#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3) +#define ZPU_RB_CLK_STATUS_PPS_DETECT   (0x1 << 4)  //spi slaves on radio -#define DB_DAC_SEN (1 << 7) -#define DB_ADC_SEN (1 << 6) +#define DB_DAC_SEN      (1 << 7) +#define DB_ADC_SEN      (1 << 6)  #define DB_RX_LSADC_SEN (1 << 5)  #define DB_RX_LSDAC_SEN (1 << 4)  #define DB_TX_LSADC_SEN (1 << 3)  #define DB_TX_LSDAC_SEN (1 << 2) -#define DB_RX_SEN (1 << 1) -#define DB_TX_SEN (1 << 0) +#define DB_RX_SEN       (1 << 1) +#define DB_TX_SEN       (1 << 0)  //-------------------------------------------------------------------  // PCIe Registers  //------------------------------------------------------------------- -static const uint32_t X300_PCIE_VID         = 0x1093; -static const uint32_t X300_PCIE_PID         = 0xC4C4; -static const uint32_t X300_USRP_PCIE_SSID   = 0x7736; -static const uint32_t X310_USRP_PCIE_SSID   = 0x76CA; -static const uint32_t X310_2940R_PCIE_SSID  = 0x772B; -static const uint32_t X310_2942R_PCIE_SSID  = 0x772C; -static const uint32_t X310_2943R_PCIE_SSID  = 0x772D; -static const uint32_t X310_2944R_PCIE_SSID  = 0x772E; -static const uint32_t X310_2950R_PCIE_SSID  = 0x772F; -static const uint32_t X310_2952R_PCIE_SSID  = 0x7730; -static const uint32_t X310_2953R_PCIE_SSID  = 0x7731; -static const uint32_t X310_2954R_PCIE_SSID  = 0x7732; +static const uint32_t X300_PCIE_VID               = 0x1093; +static const uint32_t X300_PCIE_PID               = 0xC4C4; +static const uint32_t X300_USRP_PCIE_SSID         = 0x7736; +static const uint32_t X310_USRP_PCIE_SSID         = 0x76CA; +static const uint32_t X310_2940R_40MHz_PCIE_SSID  = 0x772B; +static const uint32_t X310_2940R_120MHz_PCIE_SSID = 0x77FB; +static const uint32_t X310_2942R_40MHz_PCIE_SSID  = 0x772C; +static const uint32_t X310_2942R_120MHz_PCIE_SSID = 0x77FC; +static const uint32_t X310_2943R_40MHz_PCIE_SSID  = 0x772D; +static const uint32_t X310_2943R_120MHz_PCIE_SSID = 0x77FD; +static const uint32_t X310_2944R_40MHz_PCIE_SSID  = 0x772E; +static const uint32_t X310_2950R_40MHz_PCIE_SSID  = 0x772F; +static const uint32_t X310_2950R_120MHz_PCIE_SSID = 0x77FE; +static const uint32_t X310_2952R_40MHz_PCIE_SSID  = 0x7730; +static const uint32_t X310_2952R_120MHz_PCIE_SSID = 0x77FF; +static const uint32_t X310_2953R_40MHz_PCIE_SSID  = 0x7731; +static const uint32_t X310_2953R_120MHz_PCIE_SSID = 0x7800; +static const uint32_t X310_2954R_40MHz_PCIE_SSID  = 0x7732;  static const uint32_t FPGA_X3xx_SIG_VALUE   = 0x58333030;  static const uint32_t PCIE_FPGA_ADDR_BASE   = 0xC0000; -#define PCIE_FPGA_REG(X)                    (PCIE_FPGA_ADDR_BASE + X) +#define PCIE_FPGA_REG(X)                    (PCIE_FPGA_ADDR_BASE + (X))  static const uint32_t FPGA_PCIE_SIG_REG     = PCIE_FPGA_REG(0x0000);  static const uint32_t FPGA_CNTR_LO_REG      = PCIE_FPGA_REG(0x0004); @@ -140,8 +147,8 @@ static const uint32_t DMA_FRAME_SIZE_REG    = 0x4;  static const uint32_t DMA_SAMPLE_COUNT_REG  = 0x8;  static const uint32_t DMA_PKT_COUNT_REG     = 0xC; -#define PCIE_TX_DMA_REG(REG, CHAN)          (PCIE_TX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG) -#define PCIE_RX_DMA_REG(REG, CHAN)          (PCIE_RX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG) +#define PCIE_TX_DMA_REG(REG, CHAN)          (PCIE_TX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG)) +#define PCIE_RX_DMA_REG(REG, CHAN)          (PCIE_RX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG))  static const uint32_t DMA_CTRL_DISABLED     = 0x00000000;  static const uint32_t DMA_CTRL_ENABLED      = 0x00000002; @@ -154,15 +161,15 @@ static const uint32_t DMA_STATUS_ERROR      = 0x00000001;  static const uint32_t DMA_STATUS_BUSY       = 0x00000002;  static const uint32_t PCIE_ROUTER_REG_BASE  = PCIE_FPGA_REG(0x0500); -#define PCIE_ROUTER_REG(X)                  (PCIE_ROUTER_REG_BASE + X) +#define PCIE_ROUTER_REG(X)                  (PCIE_ROUTER_REG_BASE + (X))  static const uint32_t PCIE_ZPU_DATA_BASE    = 0x30000;  static const uint32_t PCIE_ZPU_READ_BASE    = 0x20000;  //Trig and Status share the same base  static const uint32_t PCIE_ZPU_STATUS_BASE  = 0x20000; -#define PCIE_ZPU_DATA_REG(X)                (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + X) -#define PCIE_ZPU_READ_REG(X)                (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + X) -#define PCIE_ZPU_STATUS_REG(X)              (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + X) +#define PCIE_ZPU_DATA_REG(X)                (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + (X)) +#define PCIE_ZPU_READ_REG(X)                (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + (X)) +#define PCIE_ZPU_STATUS_REG(X)              (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + (X))  static const uint32_t PCIE_ZPU_READ_START       = 0x0;  static const uint32_t PCIE_ZPU_READ_CLOBBER     = 0x80000000; diff --git a/host/lib/usrp_clock/octoclock/common.h b/host/lib/usrp_clock/octoclock/common.h index 96acbb30f..5861bc4b1 100644 --- a/host/lib/usrp_clock/octoclock/common.h +++ b/host/lib/usrp_clock/octoclock/common.h @@ -1,5 +1,5 @@  /* - * Copyright 2014 Ettus Research LLC + * Copyright 2014-2015 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 @@ -42,11 +42,11 @@ extern "C" {   * only valid C code should go in this section.   */ -//These values are placed in the octoclock_packet_t.proto_ver field +// These values are placed in the octoclock_packet_t.proto_ver field  #define OCTOCLOCK_BOOTLOADER_PROTO_VER 1234 -#define OCTOCLOCK_FW_COMPAT_NUM 2 +#define OCTOCLOCK_FW_COMPAT_NUM           3 -//UDP ports assigned for different tasks +// UDP ports assigned for different tasks  #define OCTOCLOCK_UDP_CTRL_PORT   50000  #define OCTOCLOCK_UDP_GPSDO_PORT  50001  #define OCTOCLOCK_UDP_FW_PORT     50002 @@ -98,11 +98,21 @@ typedef enum {  } ref_t;  typedef enum { -    UP, -    DOWN +    PREFER_INTERNAL, +    PREFER_EXTERNAL  } switch_pos_t; +/* + * Some versions of AVR-GCC ignore #pragma pack, so + * if AVR-GCC is being used, use __attribute__ + * instead. + */ +#ifdef AVR +#define __AVR_ALIGNED__ __attribute__((aligned(1))) +#else +#define __AVR_ALIGNED__  #pragma pack(push,1) +#endif  // Structure of values in EEPROM, starting in location 0  typedef struct { @@ -113,34 +123,37 @@ typedef struct {      uint8_t serial[10];      uint8_t name[10];      uint8_t revision; -} octoclock_fw_eeprom_t; +} octoclock_fw_eeprom_t __AVR_ALIGNED__;  typedef struct {      uint8_t external_detected;      uint8_t gps_detected;      uint8_t which_ref;      uint8_t switch_pos; -} octoclock_state_t; +} octoclock_state_t __AVR_ALIGNED__;  typedef struct {      uint8_t num_wraps;      uint8_t pos; -} gpsdo_cache_state_t; +} gpsdo_cache_state_t __AVR_ALIGNED__;  typedef struct {      uint32_t proto_ver;      uint32_t sequence;      uint8_t code;      union { -        uint16_t len; +        uint16_t crc;          gpsdo_cache_state_t state;          uint16_t poolsize;          uint16_t addr;      };      uint8_t data[256]; -} octoclock_packet_t; +    uint16_t len; +} octoclock_packet_t __AVR_ALIGNED__; +#ifndef AVR  #pragma pack(pop) +#endif  #ifdef __cplusplus  } diff --git a/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp b/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp index 93c317191..49d1a0442 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-2015 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 <uhd/usrp_clock/octoclock_eeprom.hpp>  #include <uhd/transport/udp_simple.hpp>  #include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/byte_vector.hpp>  #include <uhd/types/mac_addr.hpp>  #include <uhd/utils/byteswap.hpp>  #include <boost/assign/list_of.hpp> @@ -37,26 +38,6 @@ using namespace uhd::usrp_clock;  using namespace uhd::transport;  /*********************************************************************** - * Utility functions - **********************************************************************/ - -//! A wrapper around std::copy that takes ranges instead of iterators. -template<typename RangeSrc, typename RangeDst> inline -void byte_copy(const RangeSrc &src, RangeDst &dst){ -    std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); -} - -//! create a string from a byte vector, return empty if invalid ascii -static const std::string bytes_to_string(const byte_vector_t &bytes){ -    std::string out; -    BOOST_FOREACH(boost::uint8_t byte, bytes){ -        if (byte < 32 or byte > 127) return out; -        out += byte; -    } -    return out; -} - -/***********************************************************************   * Implementation   **********************************************************************/  void octoclock_eeprom_t::_load(){ diff --git a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp index b98d95725..ef1bc8ca0 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp @@ -357,14 +357,14 @@ void octoclock_impl::_get_state(const std::string &oc){  }  uhd::dict<ref_t, std::string> _ref_strings = boost::assign::map_list_of -    (NO_REF, "none") +    (NO_REF,   "none")      (INTERNAL, "internal")      (EXTERNAL, "external")  ;  uhd::dict<switch_pos_t, std::string> _switch_pos_strings = boost::assign::map_list_of -    (UP, "Prefer internal") -    (DOWN, "Prefer external") +    (PREFER_INTERNAL, "Prefer internal") +    (PREFER_EXTERNAL, "Prefer external")  ;  sensor_value_t octoclock_impl::_ext_ref_detected(const std::string &oc){ @@ -410,7 +410,7 @@ boost::uint32_t octoclock_impl::_get_time(const std::string &oc){  }  std::string octoclock_impl::_get_images_help_message(const std::string &addr){ -    const std::string image_name = "octoclock_r4_fw.bin"; +    const std::string image_name = "octoclock_r4_fw.hex";      //Check to see if image is in default location      std::string image_location; diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index f29318ddd..a9c9965c8 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -367,10 +367,10 @@ std::string uhd::find_utility(std::string name) {          .string();  } -std::string uhd::print_utility_error(std::string name){ +std::string uhd::print_utility_error(const std::string &name, const std::string &args){      #ifdef UHD_PLATFORM_WIN32 -    return "As an Administrator, please run:\n\n\"" + find_utility(name) + "\""; +    return "As an Administrator, please run:\n\n\"" + find_utility(name) + args +  "\"";      #else -    return "Please run:\n\n \"" + find_utility(name) + "\""; +    return "Please run:\n\n \"" + find_utility(name) + (args.empty() ? "" : (" " + args)) + "\"";      #endif  } diff --git a/host/lib/utils/platform.cpp b/host/lib/utils/platform.cpp index e2f92039e..a9cef663b 100644 --- a/host/lib/utils/platform.cpp +++ b/host/lib/utils/platform.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2012 Ettus Research LLC +// Copyright 2010-2012,2014 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,7 @@  #include <uhd/config.hpp>  #include <boost/functional/hash.hpp>  #ifdef UHD_PLATFORM_WIN32 -#include <Windows.h> +#include <windows.h>  #else  #include <unistd.h>  #endif diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp index 7c3faa37a..af25d088a 100644 --- a/host/lib/utils/thread_priority.cpp +++ b/host/lib/utils/thread_priority.cpp @@ -74,7 +74,7 @@ static void check_priority_range(float priority){  #ifdef HAVE_WIN_SETTHREADPRIORITY      #include <windows.h> -    void uhd::set_thread_priority(float priority, bool realtime){ +    void uhd::set_thread_priority(float priority, UHD_UNUSED(bool realtime)){          check_priority_range(priority);          /*  | 
