diff options
Diffstat (limited to 'host/lib')
30 files changed, 2379 insertions, 1254 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 3dfd54312..dfcb88ec9 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -15,6 +15,33 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # + +######################################################################## +# Setup Python +######################################################################## +INCLUDE(FindPythonInterp) + +MACRO(PYTHON_CHECK_MODULE module have) +    MESSAGE(STATUS "Checking for python module ${module}") +    EXECUTE_PROCESS( +        COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}" +        RESULT_VARIABLE ${have} +    ) +    IF(${have} EQUAL 0) +        MESSAGE(STATUS "Checking for python module ${module} - found") +        SET(${have} TRUE) +    ELSE(${have} EQUAL 0) +        MESSAGE(STATUS "Checking for python module ${module} - not found") +        SET(${have} FALSE) +    ENDIF(${have} EQUAL 0) +ENDMACRO(PYTHON_CHECK_MODULE) + +PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH) + +IF(NOT HAVE_PYTHON_MODULE_CHEETAH) +    MESSAGE(FATAL_ERROR "Error: Cheetah Templates needed for pre-build generation.") +ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH) +  ########################################################################  # Create a list of libuhd sources  ######################################################################## @@ -24,20 +51,63 @@ SET(libuhd_sources      load_modules.cpp      types.cpp      wax.cpp +    transport/convert_types.cpp      transport/if_addrs.cpp      transport/udp_simple.cpp -    transport/vrt.cpp      usrp/dboard/db_basic_and_lf.cpp +    usrp/dboard/db_rfx.cpp      usrp/dboard_base.cpp -    usrp/dboard_interface.cpp      usrp/simple_usrp.cpp      usrp/dboard_manager.cpp      usrp/tune_helper.cpp +) + +######################################################################## +# Generate Files +######################################################################## +MACRO(UHD_PYTHON_GEN_SOURCE_FILE pyfile outfile) +    ADD_CUSTOM_COMMAND( +        OUTPUT ${outfile} DEPENDS ${pyfile} +        COMMAND ${PYTHON_EXECUTABLE} ${pyfile} ${outfile} +        COMMENT "Calling ${pyfile} to generate ${outfile}" +    ) +    LIST(APPEND libuhd_sources ${outfile}) +ENDMACRO(UHD_PYTHON_GEN_SOURCE_FILE) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/transport/gen_vrt.py +    ${CMAKE_CURRENT_BINARY_DIR}/transport/vrt.cpp +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_adf4360_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/adf4360_regs.hpp +) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad9510_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9510_regs.hpp +) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad9777_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9777_regs.hpp +) + + +######################################################################## +# Add usrp2 sources +######################################################################## +LIST(APPEND libuhd_sources +    usrp/usrp2/clock_control.cpp      usrp/usrp2/dboard_impl.cpp -    usrp/usrp2/dboard_interface.cpp +    usrp/usrp2/dboard_iface.cpp      usrp/usrp2/dsp_impl.cpp      usrp/usrp2/io_impl.cpp      usrp/usrp2/mboard_impl.cpp +    usrp/usrp2/usrp2_iface.cpp      usrp/usrp2/usrp2_impl.cpp  ) diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py new file mode 100755 index 000000000..90230b8f9 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# +# Copyright 2008,2009 Free Software Foundation, Inc. +#  +# This file is part of GNU Radio +#  +# GNU Radio 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 asversion 3, or (at your option) +# any later version. +#  +# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import re +import os +import sys +from Cheetah.Template import Template +def parse_tmpl(_tmpl_text, **kwargs): +    return str(Template(_tmpl_text, kwargs)) +def safe_makedirs(path): +    not os.path.isdir(path) and os.makedirs(path) + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +######################################################################## +## serial control port config +######################################################################## +long_instruction               0[4]          1       8bits, 16bits +soft_reset                     0[5]          0 +lsb_first                      0[6]          0       msb, lsb +sdo_inactive                   0[7]          0       active, inactive +######################################################################## +## pll settings +######################################################################## +acounter                       4[0:5]        0 +bcounter_msb                   5[0:4]        0 +bcounter_lsb                   6[0:7]        0 +lor_enable                     7[2]          0      enb, dis +lor_ildd                       7[5:6]        0      3cyc, 6cyc, 12cyc, 24cyc +charge_pump_mode               8[0:1]        0      3state, pump_up, pump_down, normal +pll_mux_control                8[2:5]        0      off, dld_high, ndiv, dld_low, rdiv, ald_nchan, acounter, prescaler, pfd_up, pfd_down, lor_high, 3state, ald_pchan, lor_lol_high, lor_lol_low, lor_low +pfd_polarity                   8[6]          0      neg, pos +reset_all_counters             9[0]          0 +ncounter_reset                 9[1]          0 +rcounter_reset                 9[2]          0 +cp_current_setting             9[4:6]        0      0_60ma, 1_2ma, 1_8ma, 2_4ma, 3_0ma, 3_6ma, 4_2ma, 4_8ma +pll_power_down                 A[0:1]        0      normal=0, async_pd=1, sync_pd=3 +prescaler_value                A[2:4]        0      div1, div2, 2_3, 4_5, 8_9, 16_17, 32_33, div3 +b_counter_bypass               A[6]          0 +ref_counter_msb                B[0:5]        0 +ref_counter_lsb                C[0:7]        0 +antibacklash_pw                D[0:1]        0      1_3ns, 2_9ns, 6_0ns +dld_window                     D[5]          0      9_5ns, 3_5ns +lock_detect_disable            D[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 +######################################################################## +## 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 +clock_select                   45[0]               1   clk2_drives, clk1_drives +clk1_power_down                45[1]               0 +clk2_power_down                45[2]               0 +prescaler_clock_pd             45[3]               0 +refin_power_down               45[4]               0 +all_clock_inputs_pd            45[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 +######################################################################## +## function +######################################################################## +sync_detect_enable             58[0]               0    dis, enb +sync_select                    58[1]               0    1_to_0_5, 0_5_to_1 +soft_sync                      58[2]               0 +dist_power_down                58[3]               0 +sync_power_down                58[4]               0 +function_pin_select            58[5:6]             0    resetb, syncb, test, pdb +update_registers               5A[0]               0 +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_AD9510_REGS_HPP +\#define INCLUDED_AD9510_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct ad9510_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #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 +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    ad9510_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    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 +            break; +        #end for +        } +        return reg; +    } + +    boost::uint32_t get_write_reg(boost::uint16_t addr){ +        return (boost::uint32_t(addr) << 8) | get_reg(addr); +    } + +    boost::uint32_t get_read_reg(boost::uint16_t addr){ +        return (boost::uint32_t(addr) << 8) | (1 << 15); +    } + +}; + +\#endif /* INCLUDED_AD9510_REGS_HPP */ +""" + +class reg: +    def __init__(self, reg_des): +        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) +        name, addr, bit_range, default, enums = x.groups() + +        #store variables +        self._name = name +        self._addr = int(addr, 16) +        if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':')) +        else: self._addr_spec = int(bit_range), int(bit_range) +        self._default = int(default, 16) + +        #extract enum +        self._enums = list() +        if enums: +            enum_val = 0 +            for enum_str in map(str.strip, enums.split(',')): +                if '=' in enum_str: +                    enum_name, enum_val = enum_str.split('=') +                    enum_val = int(enum_val) +                else: enum_name = enum_str +                self._enums.append((enum_name, enum_val)) +                enum_val += 1 + +    def get_addr(self): return self._addr +    def get_enums(self): return self._enums +    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)) +        return self._default +    def get_stdint_type(self): +        if self.get_bit_width() <=  8: return 'uint8_t' +        if self.get_bit_width() <= 16: return 'uint16_t' +        if self.get_bit_width() <= 32: return 'uint32_t' +        if self.get_bit_width() <= 64: return 'uint64_t' +        raise Exception, 'too damn big' +    def get_shift(self): return self._addr_spec[0] +    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) +    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    safe_makedirs(os.path.dirname(sys.argv[1])) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py new file mode 100644 index 000000000..6077b61b6 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python +# +# Copyright 2008,2009 Free Software Foundation, Inc. +#  +# This file is part of GNU Radio +#  +# GNU Radio 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 asversion 3, or (at your option) +# any later version. +#  +# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import re +import os +import sys +from Cheetah.Template import Template +def parse_tmpl(_tmpl_text, **kwargs): +    return str(Template(_tmpl_text, kwargs)) +def safe_makedirs(path): +    not os.path.isdir(path) and os.makedirs(path) + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +######################################################################## +## address 0 +######################################################################## +sdio_bidirectional      0[7]     0      input, io +lsb_msb_first           0[6]     0      msb, lsb +soft_reset              0[5]     0 +sleep_mode              0[4]     0 +power_down_mode         0[3]     0 +x_1r_2r_mode            0[2]     0      2r, 1r +pll_lock_indicator      0[1]     0 +######################################################################## +## address 1 +######################################################################## +filter_interp_rate      1[6:7]   0      1x, 2x, 4x, 8x +modulation_mode         1[4:5]   0      none, fs_2, fs_4, fs_8 +zero_stuff_mode         1[3]     0 +mix_mode                1[2]     1      complex, real +modulation_form         1[1]     0      e_minus_jwt, e_plus_jwt +data_clk_pll_lock_sel   1[0]     0      pll_lock, data_clk +######################################################################## +## address 2 +######################################################################## +signed_input_data       2[7]     0      signed, unsigned +two_port_mode           2[6]     0      two_port, one_port +dataclk_driver_strength 2[5]     0      weak, strong +dataclk_invert          2[4]     0 +oneportclk_invert       2[2]     0 +iqsel_invert            2[1]     0 +iq_first                2[0]     0      i_first, q_first +######################################################################## +## address 3 +######################################################################## +data_rate_clock_output  3[7]     0      pll_lock, spi_sdo +pll_divide_ratio        3[0:1]   0      div1, div2, div4, div8 +######################################################################## +## address 4 +######################################################################## +pll_state               4[7]     0      off, on +auto_cp_control         4[6]     0      dis, enb +pll_cp_control          4[0:2]   0      50ua=0, 100ua=1, 200ua=2, 400ua=3, 800ua=7 +######################################################################## +## address 5 and 9 +######################################################################## +idac_fine_gain_adjust   5[0:7]   0 +qdac_fine_gain_adjust   9[0:7]   0 +######################################################################## +## address 6 and A +######################################################################## +idac_coarse_gain_adjust 6[0:3]   0 +qdac_coarse_gain_adjust A[0:3]   0 +######################################################################## +## address 7, 8 and B, C +######################################################################## +idac_offset_adjust_msb  7[0:7]   0 +idac_offset_adjust_lsb  8[0:1]   0 +idac_ioffset_direction  8[7]     0     out_a, out_b +qdac_offset_adjust_msb  B[0:7]   0 +qdac_offset_adjust_lsb  C[0:1]   0 +qdac_ioffset_direction  C[7]     0     out_a, out_b +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_AD9777_REGS_HPP +\#define INCLUDED_AD9777_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct ad9777_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #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 +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    ad9777_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    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 +            break; +        #end for +        } +        return reg; +    } + +    boost::uint16_t get_write_reg(boost::uint8_t addr){ +        return (boost::uint16_t(addr) << 8) | get_reg(addr); +    } + +    boost::uint16_t get_read_reg(boost::uint8_t addr){ +        return (boost::uint16_t(addr) << 8) | (1 << 7); +    } +}; + +\#endif /* INCLUDED_AD9777_REGS_HPP */ +""" + +class reg: +    def __init__(self, reg_des): +        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) +        name, addr, bit_range, default, enums = x.groups() + +        #store variables +        self._name = name +        self._addr = int(addr, 16) +        if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':'))) +        else: self._addr_spec = int(bit_range), int(bit_range) +        self._default = int(default, 16) + +        #extract enum +        self._enums = list() +        if enums: +            enum_val = 0 +            for enum_str in map(str.strip, enums.split(',')): +                if '=' in enum_str: +                    enum_name, enum_val = enum_str.split('=') +                    enum_val = int(enum_val) +                else: enum_name = enum_str +                self._enums.append((enum_name, enum_val)) +                enum_val += 1 + +    def get_addr(self): return self._addr +    def get_enums(self): return self._enums +    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)) +        return self._default +    def get_stdint_type(self): +        if self.get_bit_width() <=  8: return 'uint8_t' +        if self.get_bit_width() <= 16: return 'uint16_t' +        if self.get_bit_width() <= 32: return 'uint32_t' +        if self.get_bit_width() <= 64: return 'uint64_t' +        raise Exception, 'too damn big' +    def get_shift(self): return self._addr_spec[0] +    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) +    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    safe_makedirs(os.path.dirname(sys.argv[1])) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py new file mode 100755 index 000000000..bcad1ffd3 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# +# Copyright 2008,2009 Free Software Foundation, Inc. +#  +# This file is part of GNU Radio +#  +# GNU Radio 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 asversion 3, or (at your option) +# any later version. +#  +# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import re +import os +import sys +from Cheetah.Template import Template +def parse_tmpl(_tmpl_text, **kwargs): +    return str(Template(_tmpl_text, kwargs)) +def safe_makedirs(path): +    not os.path.isdir(path) and os.makedirs(path) + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +######################################################################## +## address 0 +######################################################################## +core_power_level         0[2:3]     0          5ma, 10ma, 15ma, 20ma +counter_operation        0[4]       0          normal, reset +muxout_control           0[5:7]     0          3state, dld, ndiv, dvdd, rdiv, nchan_od_ld, sdo, dgnd +phase_detector_polarity  0[8]       0          neg, pos +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 +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 +######################################################################## +## address 2 +######################################################################## +a_counter                2[2:6]     0 +b_counter                2[8:20]    0 +cp_gain_1                2[21]      0          set1, set2 +divide_by_2_output       2[22]      0          fund, div2 +divide_by_2_prescaler    2[23]      0          fund, div2 +######################################################################## +## address 1 +######################################################################## +r_counter                1[2:15]    0 +ablpw                    1[16:17]   0           3_0ns, 1_3ns, 6_0ns +lock_detect_precision    1[18]      0           3cycles, 5cycles +test_mode_bit            1[19]      0 +band_select_clock_div    1[20:21]   0           1, 2, 4, 8 +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_ADF4360_REGS_HPP +\#define INCLUDED_ADF4360_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct adf4360_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #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 +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    adf4360_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    enum addr_t{ +        ADDR_CONTROL = 0, +        ADDR_NCOUNTER = 2, +        ADDR_RCOUNTER = 1 +    }; + +    boost::uint32_t get_reg(addr_t addr){ +        boost::uint32_t reg = addr & 0x3; +        switch(addr){ +        #for $addr in (0, 1, 2) +        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 +            break; +        #end for +        } +        return reg; +    } +}; + +\#endif /* INCLUDED_ADF4360_REGS_HPP */ +""" + +class reg: +    def __init__(self, reg_des): +        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) +        name, addr, bit_range, default, enums = x.groups() + +        #store variables +        self._name = name +        self._addr = int(addr) +        if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':')) +        else: self._addr_spec = int(bit_range), int(bit_range) +        self._default = int(default) + +        #extract enum +        self._enums = list() +        if enums: +            enum_val = 0 +            for enum_str in map(str.strip, enums.split(',')): +                if '=' in enum_str: +                    enum_name, enum_val = enum_str.split('=') +                    enum_val = int(enum_val) +                else: enum_name = enum_str +                self._enums.append((enum_name, enum_val)) +                enum_val += 1 + +    def get_addr(self): return self._addr +    def get_enums(self): return self._enums +    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)) +        return self._default +    def get_stdint_type(self): +        if self.get_bit_width() <=  8: return 'uint8_t' +        if self.get_bit_width() <= 16: return 'uint16_t' +        if self.get_bit_width() <= 32: return 'uint32_t' +        if self.get_bit_width() <= 64: return 'uint64_t' +        raise Exception, 'too damn big' +    def get_shift(self): return self._addr_spec[0] +    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) +    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    safe_makedirs(os.path.dirname(sys.argv[1])) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp new file mode 100644 index 000000000..2a6854f50 --- /dev/null +++ b/host/lib/transport/convert_types.cpp @@ -0,0 +1,144 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/transport/convert_types.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/asio.hpp> //endianness conversion +#include <boost/cstdint.hpp> + +using namespace uhd; + +/*********************************************************************** + * Constants + **********************************************************************/ +typedef std::complex<float>          fc32_t; + +static const float shorts_per_float = float(1 << 15); +static const float floats_per_short = float(1.0/shorts_per_float); + +#define unrolled_loop(__inst, __len){ \ +    size_t __i = 0; \ +    for(; __i < (__len & ~0x3); __i+= 4){ \ +        __inst(__i+0); __inst(__i+1); \ +        __inst(__i+2); __inst(__i+3); \ +    } \ +    for(; __i < __len; __i++){ \ +        __inst(__i); \ +    } \ +} + +// set a boolean flag that indicates the endianess +#ifdef HAVE_BIG_ENDIAN +static const bool is_big_endian = true; +#else +static const bool is_big_endian = false; +#endif + +static inline void host_floats_to_usrp2_items( +    boost::uint32_t *usrp2_items, +    const fc32_t *host_floats, +    size_t num_samps +){ +    #define host_floats_to_usrp2_items_i(i){ \ +        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ +        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ +        usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ +    } +    unrolled_loop(host_floats_to_usrp2_items_i, num_samps); +} + +static inline void usrp2_items_to_host_floats( +    fc32_t *host_floats, +    const boost::uint32_t *usrp2_items, +    size_t num_samps +){ +    #define usrp2_items_to_host_floats_i(i){ \ +        boost::uint32_t item = ntohl(usrp2_items[i]); \ +        boost::int16_t real = boost::uint16_t(item >> 16); \ +        boost::int16_t imag = boost::uint16_t(item >> 0); \ +        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ +    } +    unrolled_loop(usrp2_items_to_host_floats_i, num_samps); +} + +static inline void host_items_to_usrp2_items( +    boost::uint32_t *usrp2_items, +    const boost::uint32_t *host_items, +    size_t num_samps +){ +    #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) +    if (is_big_endian){ +        std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); +    } +    else{ +        unrolled_loop(host_items_to_usrp2_items_i, num_samps); +    } +} + +static inline void usrp2_items_to_host_items( +    boost::uint32_t *host_items, +    const boost::uint32_t *usrp2_items, +    size_t num_samps +){ +    #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) +    if (is_big_endian){ +        std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); +    } +    else{ +        unrolled_loop(usrp2_items_to_host_items_i, num_samps); +    } +} + +void transport::convert_io_type_to_otw_type( +    const void *io_buff, const io_type_t &io_type, +    void *otw_buff, const otw_type_t &otw_type, +    size_t num_samps +){ +    //all we handle for now: +    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); + +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: +        host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps); +        break; +    case io_type_t::COMPLEX_INT16: +        host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps); +        break; +    default: +        throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); +    } +} + +void transport::convert_otw_type_to_io_type( +    const void *otw_buff, const otw_type_t &otw_type, +    void *io_buff, const io_type_t &io_type, +    size_t num_samps +){ +    //all we handle for now: +    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); + +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: +        usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); +        break; +    case io_type_t::COMPLEX_INT16: +        usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); +        break; +    default: +        throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); +    } +} diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 918de3ad7..38a394dee 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -54,7 +54,8 @@ void vrt::pack(      size_t &num_header_words32,    //output      size_t num_payload_words32,    //input      size_t &num_packet_words32,    //output -    size_t packet_count            //input +    size_t packet_count,           //input +    double tick_rate               //input  ){      boost::uint32_t vrt_hdr_flags; @@ -91,7 +92,7 @@ void vrt::pack(          #if $pred & $tsf_p              header_buff[$num_header_words] = htonl(0);              #set $num_header_words += 1 -            header_buff[$num_header_words] = htonl(metadata.time_spec.ticks); +            header_buff[$num_header_words] = htonl(metadata.time_spec.get_ticks(tick_rate));              #set $num_header_words += 1              #set $flags |= (0x1 << 20);          #end if @@ -127,7 +128,8 @@ void vrt::unpack(      size_t &num_header_words32,         //output      size_t &num_payload_words32,        //output      size_t num_packet_words32,          //input -    size_t &packet_count                //output +    size_t &packet_count,               //output +    double tick_rate                    //input  ){      //clear the metadata      metadata = rx_metadata_t(); @@ -180,7 +182,7 @@ void vrt::unpack(                  #set $set_has_time_spec = True              #end if              #set $num_header_words += 1 -            metadata.time_spec.ticks = ntohl(header_buff[$num_header_words]); +            metadata.time_spec.set_ticks(ntohl(header_buff[$num_header_words]), tick_rate);              #set $num_header_words += 1          #end if          ########## Trailer ########## @@ -198,9 +200,15 @@ void vrt::unpack(  }  """ -from Cheetah import Template -def parse_str(_tmpl_text, **kwargs): return str(Template.Template(_tmpl_text, kwargs)) +import os +import sys + +from Cheetah.Template import Template +def parse_tmpl(_tmpl_text, **kwargs): +    return str(Template(_tmpl_text, kwargs)) +def safe_makedirs(path): +    not os.path.isdir(path) and os.makedirs(path)  if __name__ == '__main__': -    from Cheetah import Template -    print parse_str(TMPL_TEXT, file=__file__) +    safe_makedirs(os.path.dirname(sys.argv[1])) +    open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__)) diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 1fc8ce14a..7e643abad 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -25,39 +25,74 @@  using namespace uhd::transport;  /*********************************************************************** - * Smart buffer implementation for udp zerocopy none - * - * This smart buffer implemention houses a const buffer. - * When the smart buffer is deleted, the buffer is freed. - * The memory in the const buffer is allocated with new [], - * and so the destructor frees the buffer with delete []. + * Managed receive buffer implementation for udp zero-copy asio: + *   Frees the memory held by the const buffer on done.   **********************************************************************/ -class smart_buffer_impl : public smart_buffer{ +class managed_recv_buffer_impl : public managed_recv_buffer{  public: -    smart_buffer_impl(const boost::asio::const_buffer &buff){ -        _buff = buff; +    managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ +        _done = false;      } -    ~smart_buffer_impl(void){ +    ~managed_recv_buffer_impl(void){ +        if (not _done) this->done(); +    } + +    void done(void){ +        _done = true;          delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff);      } -    const boost::asio::const_buffer &get(void) const{ +private: +    const boost::asio::const_buffer &get(void){          return _buff;      } +    const boost::asio::const_buffer _buff; +    bool _done; +}; + +/*********************************************************************** + * Managed send buffer implementation for udp zero-copy asio: + *   Sends and frees the memory held by the mutable buffer on done. + **********************************************************************/ +class managed_send_buffer_impl : public managed_send_buffer{ +public: +    managed_send_buffer_impl( +        const boost::asio::mutable_buffer &buff, +        boost::asio::ip::udp::socket *socket +    ) : _buff(buff){ +        _done = false; +        _socket = socket; +    } + +    ~managed_send_buffer_impl(void){ +        if (not _done) this->done(0); +    } + +    void done(size_t num_bytes){ +        _done = true; +        boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff); +        _socket->send(boost::asio::buffer(mem, num_bytes)); +        delete [] mem; +    } +  private: -    boost::asio::const_buffer _buff; +    const boost::asio::mutable_buffer &get(void){ +        return _buff; +    } + +    const boost::asio::mutable_buffer _buff; +    boost::asio::ip::udp::socket      *_socket; +    bool _done;  };  /*********************************************************************** - * UDP zero copy implementation class - * - * This is the portable zero copy implementation for systems - * where a faster, platform specific solution is not available. - * - * It uses boost asio udp sockets and the standard recv() class, - * and in-fact, is not actually doing a zero-copy implementation. + * Zero Copy UDP implementation with ASIO: + *   This is the portable zero copy implementation for systems + *   where a faster, platform specific solution is not available. + *   However, it is not a true zero copy implementation as each + *   send and recv requires a copy operation to/from userspace.   **********************************************************************/  class udp_zero_copy_impl : public udp_zero_copy{  public: @@ -66,8 +101,8 @@ public:      ~udp_zero_copy_impl(void);      //send/recv -    size_t send(const boost::asio::const_buffer &buff); -    smart_buffer::sptr recv(void); +    managed_recv_buffer::sptr get_recv_buff(void); +    managed_send_buffer::sptr get_send_buff(void);  private:      boost::asio::ip::udp::socket   *_socket; @@ -107,31 +142,32 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){      delete _socket;  } -size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ -    return _socket->send(boost::asio::buffer(buff)); -} - -smart_buffer::sptr udp_zero_copy_impl::recv(void){ -    size_t available = 0; - +managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){      //implement timeout through polling and sleeping +    size_t available = 0;      boost::asio::deadline_timer timer(_socket->get_io_service());      timer.expires_from_now(boost::posix_time::milliseconds(100));      while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){          boost::this_thread::sleep(boost::posix_time::milliseconds(1));      } -    //allocate memory and create buffer -    boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; -    boost::asio::mutable_buffer buff(buff_mem, available); -      //receive only if data is available +    boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];      if (available){ -        _socket->receive(boost::asio::buffer(buff)); +        available = _socket->receive(boost::asio::buffer(buff_mem, available));      } -    //create a new smart buffer to house the data -    return smart_buffer::sptr(new smart_buffer_impl(buff)); +    //create a new managed buffer to house the data +    return managed_recv_buffer::sptr( +        new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available)) +    ); +} + +managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ +    boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)]; +    return managed_send_buffer::sptr( +        new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket) +    );  }  size_t udp_zero_copy_impl::get_recv_buff_size(void){ diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp deleted file mode 100644 index bebca5db9..000000000 --- a/host/lib/transport/vrt.cpp +++ /dev/null @@ -1,547 +0,0 @@ - - - -/*********************************************************************** - * This file was generated by ./gen_vrt.py on Fri Mar 26 15:33:00 2010 - **********************************************************************/ - -#include <uhd/transport/vrt.hpp> -#include <boost/asio.hpp> //endianness conversion -#include <stdexcept> - -using namespace uhd; -using namespace uhd::transport; - -void vrt::pack( -    const tx_metadata_t &metadata, //input -    boost::uint32_t *header_buff,  //output -    size_t &num_header_words32,    //output -    size_t num_payload_words32,    //input -    size_t &num_packet_words32,    //output -    size_t packet_count            //input -){ -    boost::uint32_t vrt_hdr_flags; - -    boost::uint8_t pred = 0; -    if (metadata.has_stream_id) pred |= 0x1; -    if (metadata.has_time_spec) pred |= 0xc; - -    switch(pred){ -    case 0: -            num_header_words32 = 1; -            num_packet_words32 = 1 + num_payload_words32; -            vrt_hdr_flags = 0x0; -        break; -    case 1: -            header_buff[1] = htonl(metadata.stream_id); -            num_header_words32 = 2; -            num_packet_words32 = 2 + num_payload_words32; -            vrt_hdr_flags = 0x10000000; -        break; -    case 2: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            num_header_words32 = 3; -            num_packet_words32 = 3 + num_payload_words32; -            vrt_hdr_flags = 0x8000000; -        break; -    case 3: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            num_header_words32 = 4; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0x18000000; -        break; -    case 4: -            header_buff[1] = htonl(metadata.time_spec.secs); -            num_header_words32 = 2; -            num_packet_words32 = 2 + num_payload_words32; -            vrt_hdr_flags = 0xc00000; -        break; -    case 5: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(metadata.time_spec.secs); -            num_header_words32 = 3; -            num_packet_words32 = 3 + num_payload_words32; -            vrt_hdr_flags = 0x10c00000; -        break; -    case 6: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.secs); -            num_header_words32 = 4; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0x8c00000; -        break; -    case 7: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.secs); -            num_header_words32 = 5; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x18c00000; -        break; -    case 8: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 3; -            num_packet_words32 = 3 + num_payload_words32; -            vrt_hdr_flags = 0x100000; -        break; -    case 9: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 4; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0x10100000; -        break; -    case 10: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 5; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x8100000; -        break; -    case 11: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(0); -            header_buff[5] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 6; -            num_packet_words32 = 6 + num_payload_words32; -            vrt_hdr_flags = 0x18100000; -        break; -    case 12: -            header_buff[1] = htonl(metadata.time_spec.secs); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 4; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0xd00000; -        break; -    case 13: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(metadata.time_spec.secs); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 5; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x10d00000; -        break; -    case 14: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.secs); -            header_buff[4] = htonl(0); -            header_buff[5] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 6; -            num_packet_words32 = 6 + num_payload_words32; -            vrt_hdr_flags = 0x8d00000; -        break; -    case 15: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.secs); -            header_buff[5] = htonl(0); -            header_buff[6] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 7; -            num_packet_words32 = 7 + num_payload_words32; -            vrt_hdr_flags = 0x18d00000; -        break; -    case 16: -            num_header_words32 = 1; -            num_packet_words32 = 2 + num_payload_words32; -            vrt_hdr_flags = 0x4000000; -        break; -    case 17: -            header_buff[1] = htonl(metadata.stream_id); -            num_header_words32 = 2; -            num_packet_words32 = 3 + num_payload_words32; -            vrt_hdr_flags = 0x14000000; -        break; -    case 18: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            num_header_words32 = 3; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0xc000000; -        break; -    case 19: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            num_header_words32 = 4; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x1c000000; -        break; -    case 20: -            header_buff[1] = htonl(metadata.time_spec.secs); -            num_header_words32 = 2; -            num_packet_words32 = 3 + num_payload_words32; -            vrt_hdr_flags = 0x4c00000; -        break; -    case 21: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(metadata.time_spec.secs); -            num_header_words32 = 3; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0x14c00000; -        break; -    case 22: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.secs); -            num_header_words32 = 4; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0xcc00000; -        break; -    case 23: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.secs); -            num_header_words32 = 5; -            num_packet_words32 = 6 + num_payload_words32; -            vrt_hdr_flags = 0x1cc00000; -        break; -    case 24: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 3; -            num_packet_words32 = 4 + num_payload_words32; -            vrt_hdr_flags = 0x4100000; -        break; -    case 25: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 4; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x14100000; -        break; -    case 26: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 5; -            num_packet_words32 = 6 + num_payload_words32; -            vrt_hdr_flags = 0xc100000; -        break; -    case 27: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(0); -            header_buff[5] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 6; -            num_packet_words32 = 7 + num_payload_words32; -            vrt_hdr_flags = 0x1c100000; -        break; -    case 28: -            header_buff[1] = htonl(metadata.time_spec.secs); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 4; -            num_packet_words32 = 5 + num_payload_words32; -            vrt_hdr_flags = 0x4d00000; -        break; -    case 29: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(metadata.time_spec.secs); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 5; -            num_packet_words32 = 6 + num_payload_words32; -            vrt_hdr_flags = 0x14d00000; -        break; -    case 30: -            header_buff[1] = htonl(0); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(metadata.time_spec.secs); -            header_buff[4] = htonl(0); -            header_buff[5] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 6; -            num_packet_words32 = 7 + num_payload_words32; -            vrt_hdr_flags = 0xcd00000; -        break; -    case 31: -            header_buff[1] = htonl(metadata.stream_id); -            header_buff[2] = htonl(0); -            header_buff[3] = htonl(0); -            header_buff[4] = htonl(metadata.time_spec.secs); -            header_buff[5] = htonl(0); -            header_buff[6] = htonl(metadata.time_spec.ticks); -            num_header_words32 = 7; -            num_packet_words32 = 8 + num_payload_words32; -            vrt_hdr_flags = 0x1cd00000; -        break; -    } - -    //set the burst flags -    if (metadata.start_of_burst) vrt_hdr_flags |= 0x2000000; -    if (metadata.end_of_burst)   vrt_hdr_flags |= 0x1000000; - -    //fill in complete header word -    header_buff[0] = htonl(vrt_hdr_flags | -        ((packet_count & 0xf) << 16) | -        (num_packet_words32 & 0xffff) -    ); -} - -void vrt::unpack( -    rx_metadata_t &metadata,            //output -    const boost::uint32_t *header_buff, //input -    size_t &num_header_words32,         //output -    size_t &num_payload_words32,        //output -    size_t num_packet_words32,          //input -    size_t &packet_count                //output -){ -    //clear the metadata -    metadata = rx_metadata_t(); - -    //extract vrt header -    boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]); -    size_t packet_words32 = vrt_hdr_word & 0xffff; -    packet_count = (vrt_hdr_word >> 16) & 0xf; - -    //failure cases -    if (packet_words32 == 0 or num_packet_words32 < packet_words32) -        throw std::runtime_error("bad vrt header or packet fragment"); -    if (vrt_hdr_word & (0x7 << 29)) -        throw std::runtime_error("unsupported vrt packet type"); - -    boost::uint8_t pred = 0; -    if(vrt_hdr_word & 0x10000000) pred |= 0x1; -    if(vrt_hdr_word & 0x8000000) pred |= 0x2; -    if(vrt_hdr_word & 0xc00000) pred |= 0x4; -    if(vrt_hdr_word & 0x300000) pred |= 0x8; -    if(vrt_hdr_word & 0x4000000) pred |= 0x10; - -    switch(pred){ -    case 0: -            num_header_words32 = 1; -            num_payload_words32 = packet_words32 - 1; -        break; -    case 1: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            num_header_words32 = 2; -            num_payload_words32 = packet_words32 - 2; -        break; -    case 2: -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 3; -        break; -    case 3: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 4: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[1]); -            num_header_words32 = 2; -            num_payload_words32 = packet_words32 - 2; -        break; -    case 5: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[2]); -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 3; -        break; -    case 6: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 7: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 8: -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[2]); -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 3; -        break; -    case 9: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 10: -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 11: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[5]); -            num_header_words32 = 6; -            num_payload_words32 = packet_words32 - 6; -        break; -    case 12: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[1]); -            metadata.time_spec.ticks = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 13: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[2]); -            metadata.time_spec.ticks = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 14: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[3]); -            metadata.time_spec.ticks = ntohl(header_buff[5]); -            num_header_words32 = 6; -            num_payload_words32 = packet_words32 - 6; -        break; -    case 15: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[4]); -            metadata.time_spec.ticks = ntohl(header_buff[6]); -            num_header_words32 = 7; -            num_payload_words32 = packet_words32 - 7; -        break; -    case 16: -            num_header_words32 = 1; -            num_payload_words32 = packet_words32 - 2; -        break; -    case 17: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            num_header_words32 = 2; -            num_payload_words32 = packet_words32 - 3; -        break; -    case 18: -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 19: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 20: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[1]); -            num_header_words32 = 2; -            num_payload_words32 = packet_words32 - 3; -        break; -    case 21: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[2]); -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 22: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 23: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 6; -        break; -    case 24: -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[2]); -            num_header_words32 = 3; -            num_payload_words32 = packet_words32 - 4; -        break; -    case 25: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 26: -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 6; -        break; -    case 27: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.ticks = ntohl(header_buff[5]); -            num_header_words32 = 6; -            num_payload_words32 = packet_words32 - 7; -        break; -    case 28: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[1]); -            metadata.time_spec.ticks = ntohl(header_buff[3]); -            num_header_words32 = 4; -            num_payload_words32 = packet_words32 - 5; -        break; -    case 29: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[2]); -            metadata.time_spec.ticks = ntohl(header_buff[4]); -            num_header_words32 = 5; -            num_payload_words32 = packet_words32 - 6; -        break; -    case 30: -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[3]); -            metadata.time_spec.ticks = ntohl(header_buff[5]); -            num_header_words32 = 6; -            num_payload_words32 = packet_words32 - 7; -        break; -    case 31: -            metadata.has_stream_id = true; -            metadata.stream_id = ntohl(header_buff[1]); -            metadata.has_time_spec = true; -            metadata.time_spec.secs = ntohl(header_buff[4]); -            metadata.time_spec.ticks = ntohl(header_buff[6]); -            num_header_words32 = 7; -            num_payload_words32 = packet_words32 - 8; -        break; -    } -} - diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 61a63b710..0fd2522cf 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -26,6 +26,7 @@  #include <uhd/types/otw_type.hpp>  #include <uhd/types/io_type.hpp>  #include <boost/algorithm/string.hpp> +#include <boost/math/special_functions/round.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp>  #include <boost/cstdint.hpp> @@ -54,8 +55,8 @@ freq_range_t::freq_range_t(double min_, double max_){  tune_result_t::tune_result_t(void){      target_inter_freq = 0.0;      actual_inter_freq = 0.0; -    target_dxc_freq = 0.0; -    actual_dxc_freq = 0.0; +    target_dsp_freq = 0.0; +    actual_dsp_freq = 0.0;      spectrum_inverted = false;  } @@ -101,29 +102,26 @@ tx_metadata_t::tx_metadata_t(void){  /***********************************************************************   * time spec   **********************************************************************/ -time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){ +time_spec_t::time_spec_t(boost::uint32_t new_secs, double new_nsecs){      secs = new_secs; -    ticks = new_ticks; +    nsecs = new_nsecs;  } -static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); -static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second()); +boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ +    return boost::math::iround(nsecs*tick_rate*1e-9); +} -time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ -    boost::posix_time::time_duration td = time - epoch; -    secs = boost::uint32_t(td.total_seconds()); -    double time_ticks_per_device_ticks = time_tick_rate/tick_rate; -    ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); +void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){ +    nsecs = double(ticks)*1e9/tick_rate;  }  /***********************************************************************   * device addr   **********************************************************************/  std::string device_addr_t::to_string(void) const{ -    const device_addr_t &device_addr = *this;      std::stringstream ss; -    BOOST_FOREACH(std::string key, device_addr.keys()){ -        ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; +    BOOST_FOREACH(std::string key, this->keys()){ +        ss << boost::format("%s: %s") % key % (*this)[key] << std::endl;      }      return ss.str();  } @@ -137,9 +135,8 @@ static std::string trim(const std::string &in){  std::string device_addr_t::to_args_str(void) const{      std::string args_str; -    const device_addr_t &device_addr = *this; -    BOOST_FOREACH(const std::string &key, device_addr.keys()){ -        args_str += key + pair_delim + device_addr[key] + arg_delim; +    BOOST_FOREACH(const std::string &key, this->keys()){ +        args_str += key + pair_delim + (*this)[key] + arg_delim;      }      return args_str;  } diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 3c14e473e..aad2398d8 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -75,11 +75,11 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){      return dboard_base::sptr(new basic_tx(args, 32e6));  } -UHD_STATIC_BLOCK(reg_dboards){ +UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){      dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX"); -    dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b")); +    dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("AB")("A")("B"));      dboard_manager::register_dboard(0x000e, &make_lf_tx,    "LF TX"); -    dboard_manager::register_dboard(0x000f, &make_lf_rx,    "LF RX",    list_of("ab")("a")("b")); +    dboard_manager::register_dboard(0x000f, &make_lf_rx,    "LF RX",    list_of("AB")("A")("B"));  }  /*********************************************************************** @@ -138,12 +138,8 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_ENABLED: -        val = true; //always enabled -        return; -      case SUBDEV_PROP_QUADRATURE: -        val = (get_subdev_name() == "ab"); //only quadrature in ab mode +        val = (get_subdev_name() == "AB"); //only quadrature in ab mode          return;      case SUBDEV_PROP_IQ_SWAPPED: @@ -175,9 +171,6 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){          ASSERT_THROW(val.as<std::string>() == std::string(""));          return; -    case SUBDEV_PROP_ENABLED: -        return; // it wont do you much good, but you can set it -      case SUBDEV_PROP_FREQ:          return; // it wont do you much good, but you can set it @@ -240,10 +233,6 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_ENABLED: -        val = true; //always enabled -        return; -      case SUBDEV_PROP_QUADRATURE:          val = true;          return; @@ -277,9 +266,6 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){          ASSERT_THROW(val.as<std::string>() == std::string(""));          return; -    case SUBDEV_PROP_ENABLED: -        return; // it wont do you much good, but you can set it -      case SUBDEV_PROP_FREQ:          return; // it wont do you much good, but you can set it diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp new file mode 100644 index 000000000..cd5b8447b --- /dev/null +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -0,0 +1,517 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +static const bool rfx_debug = false; + +// IO Pin functions +#define POWER_IO     (1 << 7)   // Low enables power supply +#define ANTSW_IO     (1 << 6)   // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2 +#define MIXER_IO     (1 << 5)   // Enable appropriate mixer +#define LOCKDET_MASK (1 << 2)   // Input pin + +// Mixer constants +#define MIXER_ENB    MIXER_IO +#define MIXER_DIS    0 + +// Power constants +#define POWER_UP     0 +#define POWER_DOWN   POWER_IO + +// Antenna constants +#define ANT_TX       0          //the tx line is transmitting +#define ANT_RX       ANTSW_IO   //the tx line is receiving +#define ANT_TXRX     0          //the rx line is on txrx +#define ANT_RX2      ANTSW_IO   //the rx line in on rx2 +#define ANT_XX       0          //dont care how the antenna is set + +#include "adf4360_regs.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/math/special_functions/round.hpp> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The RFX series of dboards + **********************************************************************/ +static const float _max_rx_pga0_gain = 45; + +class rfx_xcvr : public xcvr_dboard_base{ +public: +    rfx_xcvr( +        ctor_args_t const& args, +        const freq_range_t &freq_range, +        bool rx_div2, bool tx_div2 +    ); +    ~rfx_xcvr(void); + +    void rx_get(const wax::obj &key, wax::obj &val); +    void rx_set(const wax::obj &key, const wax::obj &val); + +    void tx_get(const wax::obj &key, wax::obj &val); +    void tx_set(const wax::obj &key, const wax::obj &val); + +private: +    freq_range_t _freq_range; +    uhd::dict<dboard_iface::unit_t, bool> _div2; +    double       _rx_lo_freq, _tx_lo_freq; +    std::string  _rx_ant; +    float        _rx_pga0_gain; + +    void set_rx_lo_freq(double freq); +    void set_tx_lo_freq(double freq); +    void set_rx_ant(const std::string &ant); +    void set_rx_pga0_gain(float gain); + +    /*! +     * Set the LO frequency for the particular dboard unit. +     * \param unit which unit rx or tx +     * \param target_freq the desired frequency in Hz +     * \return the actual frequency in Hz +     */ +    double set_lo_freq(dboard_iface::unit_t unit, double target_freq); +}; + +/*********************************************************************** + * Register the RFX dboards (min freq, max freq, rx div2, tx div2) + **********************************************************************/ +static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true)); +} + +static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6), true, true)); +} + +static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6), false, false)); +} + +static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6), true, true)); +} + +static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6), false, false)); +} + +UHD_STATIC_BLOCK(reg_rfx_dboards){ +    dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B"); +    dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B"); + +    dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B"); +    dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B"); + +    dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B"); +    dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B"); + +    dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B"); +    dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B"); + +    dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B"); +    dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +rfx_xcvr::rfx_xcvr( +    ctor_args_t const& args, +    const freq_range_t &freq_range, +    bool rx_div2, bool tx_div2 +) : xcvr_dboard_base(args){ +    _freq_range = freq_range; +    _div2[dboard_iface::UNIT_RX] = rx_div2; +    _div2[dboard_iface::UNIT_TX] = tx_div2; + +    //enable the clocks that we need +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + +    //set the gpio directions +    boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO; +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables); +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables); + +    //setup the tx atr (this does not change with antenna) +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        POWER_UP | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     POWER_UP | ANT_RX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     POWER_UP | ANT_TX | MIXER_ENB); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_TX | MIXER_ENB); + +    //setup the rx atr (this does not change with antenna) +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        POWER_UP | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     POWER_UP | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_RX2| MIXER_ENB); + +    //set some default values +    set_rx_lo_freq((_freq_range.min + _freq_range.max)/2.0); +    set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0); +    set_rx_ant("RX2"); +    set_rx_pga0_gain(0); +} + +rfx_xcvr::~rfx_xcvr(void){ +    /* NOP */ +} + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void rfx_xcvr::set_rx_lo_freq(double freq){ +    _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq); +} + +void rfx_xcvr::set_tx_lo_freq(double freq){ +    _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq); +} + +void rfx_xcvr::set_rx_ant(const std::string &ant){ +    //validate input +    ASSERT_THROW(ant == "TX/RX" or ant == "RX2"); + +    //set the rx atr regs that change with antenna setting +    this->get_iface()->set_atr_reg( +        dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, +        POWER_UP | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2) +    ); + +    //shadow the setting +    _rx_ant = ant; +} + +void rfx_xcvr::set_rx_pga0_gain(float gain){ +    //clip the input +    gain = std::clip<float>(gain, 0, _max_rx_pga0_gain); + +    //voltage level constants +    static const float max_volts = float(.2), min_volts = float(1.2); +    static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain; + +    //calculate the voltage for the aux dac +    float dac_volts = gain*slope + min_volts; + +    //write the new voltage to the aux dac +    this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 1, dac_volts); + +    //shadow the setting (does not account for precision loss) +    _rx_pga0_gain = gain; +} + +double rfx_xcvr::set_lo_freq( +    dboard_iface::unit_t unit, +    double target_freq +){ +    if (rfx_debug) std::cerr << boost::format( +        "RFX tune: target frequency %f Mhz" +    ) % (target_freq/1e6) << std::endl; + +    //clip the input +    target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max); +    if (_div2[unit]) target_freq *= 2; + +    //map prescalers to the register enums +    static const uhd::dict<int, adf4360_regs_t::prescaler_value_t> prescaler_to_enum = map_list_of +        (8,  adf4360_regs_t::PRESCALER_VALUE_8_9) +        (16, adf4360_regs_t::PRESCALER_VALUE_16_17) +        (32, adf4360_regs_t::PRESCALER_VALUE_32_33) +    ; + +    //map band select clock dividers to enums +    static const uhd::dict<int, adf4360_regs_t::band_select_clock_div_t> bandsel_to_enum = map_list_of +        (1, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_1) +        (2, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_2) +        (4, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_4) +        (8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8) +    ; + +    double actual_freq, ref_freq = this->get_iface()->get_clock_rate(unit); +    int R, BS, P, B, A; + +    /* +     * The goal here to to loop though possible R dividers, +     * band select clock dividers, and prescaler values. +     * Calculate the A and B counters for each set of values. +     * The loop exists when it meets all of the constraints. +     * The resulting loop values are loaded into the registers. +     * +     * fvco = [P*B + A] * fref/R +     * fvco*R/fref = P*B + A = N +     */ +    for(R = 2; R <= 32; R+=2){ +        BOOST_FOREACH(BS, bandsel_to_enum.keys()){ +            if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock +            BOOST_FOREACH(P, prescaler_to_enum.keys()){ +                //calculate B and A from N +                double N = target_freq*R/ref_freq; +                B = int(std::floor(N/P)); +                A = boost::math::iround(N - P*B); +                if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B +                //calculate the actual frequency +                actual_freq = double(P*B + A)*ref_freq/R; +                if (actual_freq/P > 300e6) continue; //constraint on prescaler output +                //constraints met: exit loop +                goto done_loop; +            } +        } +    } done_loop: + +    if (rfx_debug) std::cerr << boost::format( +        "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d" +    ) % R % BS % P % B % A << std::endl; + +    //load the register values +    adf4360_regs_t regs; +    regs.core_power_level        = adf4360_regs_t::CORE_POWER_LEVEL_10MA; +    regs.counter_operation       = adf4360_regs_t::COUNTER_OPERATION_NORMAL; +    regs.muxout_control          = adf4360_regs_t::MUXOUT_CONTROL_DLD; +    regs.phase_detector_polarity = adf4360_regs_t::PHASE_DETECTOR_POLARITY_POS; +    regs.charge_pump_output      = adf4360_regs_t::CHARGE_PUMP_OUTPUT_NORMAL; +    regs.cp_gain_0               = adf4360_regs_t::CP_GAIN_0_SET1; +    regs.mute_till_ld            = adf4360_regs_t::MUTE_TILL_LD_ENB; +    regs.output_power_level      = adf4360_regs_t::OUTPUT_POWER_LEVEL_3_5MA; +    regs.current_setting1        = adf4360_regs_t::CURRENT_SETTING1_0_31MA; +    regs.current_setting2        = adf4360_regs_t::CURRENT_SETTING2_0_31MA; +    regs.power_down              = adf4360_regs_t::POWER_DOWN_NORMAL_OP; +    regs.prescaler_value         = prescaler_to_enum[P]; +    regs.a_counter               = A; +    regs.b_counter               = B; +    regs.cp_gain_1               = adf4360_regs_t::CP_GAIN_1_SET1; +    regs.divide_by_2_output      = (_div2[unit])? +                                    adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 : +                                    adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ; +    regs.divide_by_2_prescaler   = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND; +    regs.r_counter               = R; +    regs.ablpw                   = adf4360_regs_t::ABLPW_3_0NS; +    regs.lock_detect_precision   = adf4360_regs_t::LOCK_DETECT_PRECISION_5CYCLES; +    regs.test_mode_bit           = 0; +    regs.band_select_clock_div   = bandsel_to_enum[BS]; + +    //write the registers +    std::vector<adf4360_regs_t::addr_t> addrs = list_of //correct power-up sequence to write registers (R, C, N) +        (adf4360_regs_t::ADDR_RCOUNTER) +        (adf4360_regs_t::ADDR_CONTROL) +        (adf4360_regs_t::ADDR_NCOUNTER) +    ; +    BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){ +        this->get_iface()->write_spi( +            unit, spi_config_t::EDGE_RISE, +            regs.get_reg(addr), 24 +        ); +    } + +    //return the actual frequency +    if (_div2[unit]) actual_freq /= 2; +    if (rfx_debug) std::cerr << boost::format( +        "RFX tune: actual frequency %f Mhz" +    ) % (actual_freq/1e6) << std::endl; +    return actual_freq; +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = dboard_id::to_string(get_rx_id()); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        ASSERT_THROW(name == "PGA0"); +        val = _rx_pga0_gain; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        ASSERT_THROW(name == "PGA0"); +        val = gain_range_t(0, _max_rx_pga0_gain, float(0.022)); +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(1, "PGA0"); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _rx_lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = _freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = _rx_ant; +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES:{ +            prop_names_t ants = list_of("TX/RX")("RX2"); +            val = ants; +        } +        return; + +    case SUBDEV_PROP_QUADRATURE: +        val = true; +        return; + +    case SUBDEV_PROP_IQ_SWAPPED: +        val = true; +        return; + +    case SUBDEV_PROP_SPECTRUM_INVERTED: +        val = false; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; +    } +} + +void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        set_rx_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        ASSERT_THROW(name == "PGA0"); +        set_rx_pga0_gain(val.as<float>()); +        return; + +    case SUBDEV_PROP_ANTENNA: +        set_rx_ant(val.as<std::string>()); +        return; + +    default: +        throw std::runtime_error(str(boost::format( +            "Error: trying to set read-only property on %s subdev" +        ) % dboard_id::to_string(get_rx_id()))); +    } +} + +/*********************************************************************** + * TX Get and Set + **********************************************************************/ +void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ +        wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = dboard_id::to_string(get_tx_id()); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        val = float(0); +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        val = gain_range_t(0, 0, 0); +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_FREQ: +        val = _tx_lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = _freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = std::string("TX/RX"); +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = prop_names_t(1, "TX/RX"); +        return; + +    case SUBDEV_PROP_QUADRATURE: +        val = true; +        return; + +    case SUBDEV_PROP_IQ_SWAPPED: +        val = false; +        return; + +    case SUBDEV_PROP_SPECTRUM_INVERTED: +        val = false; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = true; +        return; +    } +} + +void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        set_tx_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        //no gains to set! +        return; + +    case SUBDEV_PROP_ANTENNA: +        //its always set to tx/rx, so we only allow this value +        ASSERT_THROW(val.as<std::string>() == "TX/RX"); +        return; + +    default: +        throw std::runtime_error(str(boost::format( +            "Error: trying to set read-only property on %s subdev" +        ) % dboard_id::to_string(get_tx_id()))); +    } +} diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp index 09d3bbfd4..68e4743d1 100644 --- a/host/lib/usrp/dboard_base.cpp +++ b/host/lib/usrp/dboard_base.cpp @@ -25,7 +25,7 @@ using namespace uhd::usrp;   * dboard_base dboard dboard_base class   **********************************************************************/  dboard_base::dboard_base(ctor_args_t const& args){ -    boost::tie(_subdev_name, _dboard_interface, _rx_id, _tx_id) = args; +    boost::tie(_subdev_name, _dboard_iface, _rx_id, _tx_id) = args;  }  dboard_base::~dboard_base(void){ @@ -36,8 +36,8 @@ std::string dboard_base::get_subdev_name(void){      return _subdev_name;  } -dboard_interface::sptr dboard_base::get_interface(void){ -    return _dboard_interface; +dboard_iface::sptr dboard_base::get_iface(void){ +    return _dboard_iface;  }  dboard_id_t dboard_base::get_rx_id(void){ diff --git a/host/lib/usrp/dboard_interface.cpp b/host/lib/usrp/dboard_interface.cpp deleted file mode 100644 index c40c9b398..000000000 --- a/host/lib/usrp/dboard_interface.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/dboard_interface.hpp> - -using namespace uhd::usrp; - -dboard_interface::dboard_interface(void){ -    /* NOP */ -} - -dboard_interface::~dboard_interface(void){ -    /* NOP */ -} - -void dboard_interface::write_spi( -    spi_dev_t dev, -    spi_edge_t edge, -    const byte_vector_t &buf -){ -    transact_spi(dev, edge, buf, false); //dont readback -} - -dboard_interface::byte_vector_t dboard_interface::read_spi( -    spi_dev_t dev, -    spi_edge_t edge, -    size_t num_bytes -){ -    byte_vector_t buf(num_bytes, 0x00); //dummy data -    return transact_spi(dev, edge, buf, true); //readback -} - -dboard_interface::byte_vector_t dboard_interface::read_write_spi( -    spi_dev_t dev, -    spi_edge_t edge, -    const byte_vector_t &buf -){ -    return transact_spi(dev, edge, buf, true); //readback -} diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 4cf2e5820..06f8c55b6 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -25,6 +25,7 @@  #include <boost/format.hpp>  #include <boost/bind.hpp>  #include <boost/foreach.hpp> +#include <boost/assign/list_of.hpp>  using namespace uhd;  using namespace uhd::usrp; @@ -124,11 +125,11 @@ public:      dboard_manager_impl(          dboard_id_t rx_dboard_id,          dboard_id_t tx_dboard_id, -        dboard_interface::sptr interface +        dboard_iface::sptr iface      );      ~dboard_manager_impl(void); -    //dboard_interface +    //dboard_iface      prop_names_t get_rx_subdev_names(void);      prop_names_t get_tx_subdev_names(void);      wax::obj get_rx_subdev(const std::string &subdev_name); @@ -140,8 +141,8 @@ private:      //the subdevice proxy is internal to the cpp file      uhd::dict<std::string, subdev_proxy::sptr> _rx_dboards;      uhd::dict<std::string, subdev_proxy::sptr> _tx_dboards; -    dboard_interface::sptr _interface; -    void set_nice_gpio_pins(void); +    dboard_iface::sptr _iface; +    void set_nice_dboard_if(void);  };  /*********************************************************************** @@ -150,10 +151,10 @@ private:  dboard_manager::sptr dboard_manager::make(      dboard_id_t rx_dboard_id,      dboard_id_t tx_dboard_id, -    dboard_interface::sptr interface +    dboard_iface::sptr iface  ){      return dboard_manager::sptr( -        new dboard_manager_impl(rx_dboard_id, tx_dboard_id, interface) +        new dboard_manager_impl(rx_dboard_id, tx_dboard_id, iface)      );  } @@ -189,9 +190,9 @@ static args_t get_dboard_args(  dboard_manager_impl::dboard_manager_impl(      dboard_id_t rx_dboard_id,      dboard_id_t tx_dboard_id, -    dboard_interface::sptr interface +    dboard_iface::sptr iface  ){ -    _interface = interface; +    _iface = iface;      dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;      boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx"); @@ -200,14 +201,14 @@ dboard_manager_impl::dboard_manager_impl(      boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");      //initialize the gpio pins before creating subdevs -    set_nice_gpio_pins(); +    set_nice_dboard_if();      //make xcvr subdevs (make one subdev for both rx and tx dboards)      if (rx_dboard_ctor == tx_dboard_ctor){          ASSERT_THROW(rx_subdevs == tx_subdevs);          BOOST_FOREACH(const std::string &subdev, rx_subdevs){              dboard_base::sptr xcvr_dboard = rx_dboard_ctor( -                dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id) +                dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, tx_dboard_id)              );              //create a rx proxy for this xcvr board              _rx_dboards[subdev] = subdev_proxy::sptr( @@ -225,7 +226,7 @@ dboard_manager_impl::dboard_manager_impl(          //make the rx subdevs          BOOST_FOREACH(const std::string &subdev, rx_subdevs){              dboard_base::sptr rx_dboard = rx_dboard_ctor( -                dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, dboard_id::NONE) +                dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, dboard_id::NONE)              );              //create a rx proxy for this rx board              _rx_dboards[subdev] = subdev_proxy::sptr( @@ -235,7 +236,7 @@ dboard_manager_impl::dboard_manager_impl(          //make the tx subdevs          BOOST_FOREACH(const std::string &subdev, tx_subdevs){              dboard_base::sptr tx_dboard = tx_dboard_ctor( -                dboard_base::ctor_args_t(subdev, interface, dboard_id::NONE, tx_dboard_id) +                dboard_base::ctor_args_t(subdev, iface, dboard_id::NONE, tx_dboard_id)              );              //create a tx proxy for this tx board              _tx_dboards[subdev] = subdev_proxy::sptr( @@ -246,7 +247,7 @@ dboard_manager_impl::dboard_manager_impl(  }  dboard_manager_impl::~dboard_manager_impl(void){ -    set_nice_gpio_pins(); +    set_nice_dboard_if();  }  prop_names_t dboard_manager_impl::get_rx_subdev_names(void){ @@ -273,12 +274,17 @@ wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){      return _tx_dboards[subdev_name]->get_link();  } -void dboard_manager_impl::set_nice_gpio_pins(void){ -    //std::cout << "Set nice GPIO pins" << std::endl; - -    _interface->set_gpio_ddr(dboard_interface::GPIO_BANK_RX, 0x0000); //all inputs -    _interface->set_atr_reg(dboard_interface::GPIO_BANK_RX, dboard_interface::ATR_REG_IDLE, 0x0000); //all low - -    _interface->set_gpio_ddr(dboard_interface::GPIO_BANK_TX, 0x0000); //all inputs -    _interface->set_atr_reg(dboard_interface::GPIO_BANK_TX, dboard_interface::ATR_REG_IDLE, 0x0000); //all low +void dboard_manager_impl::set_nice_dboard_if(void){ +    //make a list of possible unit types +    std::vector<dboard_iface::unit_t> units = boost::assign::list_of +        (dboard_iface::UNIT_RX) +        (dboard_iface::UNIT_TX) +    ; + +    //set nice settings on each unit +    BOOST_FOREACH(dboard_iface::unit_t unit, units){ +        _iface->set_gpio_ddr(unit, 0x0000); //all inputs +        _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low +        _iface->set_clock_enabled(unit, false); //clock off +    }  } diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index fb3cc8eec..11ee3a798 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -83,10 +83,6 @@ public:          _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;      } -    double get_clock_rate(void){ -        return _mboard[MBOARD_PROP_CLOCK_RATE].as<double>(); -    } -      /*******************************************************************       * RX methods       ******************************************************************/ diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index 2fb15064c..a7d695b4e 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -74,8 +74,8 @@ static tune_result_t tune_xx_subdev_and_dxc(      tune_result_t tune_result;      tune_result.target_inter_freq = target_inter_freq;      tune_result.actual_inter_freq = actual_inter_freq; -    tune_result.target_dxc_freq = target_dxc_freq; -    tune_result.actual_dxc_freq = actual_dxc_freq; +    tune_result.target_dsp_freq = target_dxc_freq; +    tune_result.actual_dsp_freq = actual_dxc_freq;      tune_result.spectrum_inverted = inverted;      return tune_result;  } diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp new file mode 100644 index 000000000..dcd7ce9da --- /dev/null +++ b/host/lib/usrp/usrp2/clock_control.cpp @@ -0,0 +1,156 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp2_impl.hpp" +#include "clock_control.hpp" +#include "ad9510_regs.hpp" +#include "usrp2_regs.hpp" //spi slave constants +#include <boost/cstdint.hpp> + +using namespace uhd::usrp; + +/*! + * A usrp2 clock control specific to the ad9510 ic. + */ +class clock_control_ad9510 : public clock_control{ +public: +    clock_control_ad9510(usrp2_iface::sptr iface){ +        _iface = iface; + +        _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; +        this->write_reg(0x09); + +        // Setup the clock registers to 100MHz: +        //  This was already done by the firmware (or the host couldnt communicate). +        //  We could remove this part, and just leave it to the firmware. +        //  But why not leave it in for those who want to mess with clock settings? +        //  100mhz = 10mhz/R * (P*B + A) + +        _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL; +        _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2; +        this->write_reg(0x0A); + +        _ad9510_regs.acounter = 0; +        this->write_reg(0x04); + +        _ad9510_regs.bcounter_msb = 0; +        _ad9510_regs.bcounter_lsb = 5; +        this->write_reg(0x05); +        this->write_reg(0x06); + +        _ad9510_regs.ref_counter_msb = 0; +        _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 +        this->write_reg(0x0B); +        this->write_reg(0x0C); + +        /* regs will be updated in commands below */ + +        this->enable_external_ref(false); +        this->enable_rx_dboard_clock(false); +        this->enable_tx_dboard_clock(false); + +        /* private clock enables, must be set here */ +        this->enable_dac_clock(true); +        this->enable_adc_clock(true); + +    } + +    ~clock_control_ad9510(void){ +        /* private clock enables, must be set here */ +        this->enable_dac_clock(false); +        this->enable_adc_clock(false); +    } + +    //uses output clock 7 (cmos) +    void enable_rx_dboard_clock(bool enb){ +        _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; +        _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; +        _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; +        this->write_reg(0x43); +        this->update_regs(); +    } + +    //uses output clock 6 (cmos) +    void enable_tx_dboard_clock(bool enb){ +        _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; +        _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; +        _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; +        this->write_reg(0x42); +        this->update_regs(); +    } + +    /*! +     * If we are to use an external reference, enable the charge pump. +     * \param enb true to enable the CP +     */ +    void enable_external_ref(bool enb){ +        _ad9510_regs.charge_pump_mode = (enb)? +            ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL : +            ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ; +        _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH; +        _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS; +        this->write_reg(0x08); +        this->update_regs(); +    } + +private: +    /*! +     * Write a single register to the spi regs. +     * \param addr the address to write +     */ +    void write_reg(boost::uint8_t addr){ +        boost::uint32_t data = _ad9510_regs.get_write_reg(addr); +        _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/); +    } + +    /*! +     * Tells the ad9510 to latch the settings into the operational registers. +     */ +    void update_regs(void){ +        _ad9510_regs.update_registers = 1; +        this->write_reg(0x5a); +    } + +    //uses output clock 3 (pecl) +    void enable_dac_clock(bool enb){ +        _ad9510_regs.power_down_lvpecl_out3 = (enb)? +            ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : +            ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; +        _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; +        this->write_reg(0x3F); +        this->update_regs(); +    } + +    //uses output clock 4 (lvds) +    void enable_adc_clock(bool enb){ +        _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; +        _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; +        _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; +        this->write_reg(0x40); +        this->update_regs(); +    } + +    usrp2_iface::sptr _iface; +    ad9510_regs_t _ad9510_regs; +}; + +/*********************************************************************** + * Public make function for the ad9510 clock control + **********************************************************************/ +clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){ +    return clock_control::sptr(new clock_control_ad9510(iface)); +} diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_control.hpp new file mode 100644 index 000000000..b64a53196 --- /dev/null +++ b/host/lib/usrp/usrp2/clock_control.hpp @@ -0,0 +1,60 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_CLOCK_CONTROL_HPP +#define INCLUDED_CLOCK_CONTROL_HPP + +#include "usrp2_iface.hpp" +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +class clock_control : boost::noncopyable{ +public: +    typedef boost::shared_ptr<clock_control> sptr; + +    /*! +     * Make a clock config for the ad9510 ic. +     * \param _iface a pointer to the usrp2 interface object +     * \return a new clock control object +     */ +    static sptr make_ad9510(usrp2_iface::sptr iface); + +    /*! +     * Enable/disable the rx dboard clock. +     * \param enb true to enable +     */ +    virtual void enable_rx_dboard_clock(bool enb) = 0; + +    /*! +     * Enable/disable the tx dboard clock. +     * \param enb true to enable +     */ +    virtual void enable_tx_dboard_clock(bool enb) = 0; + +    /*! +     * Enable/disable external reference. +     * \param enb true to enable +     */ +    virtual void enable_external_ref(bool enb) = 0; + +    /*! +     * TODO other clock control api here.... +     */ + +}; + +#endif /* INCLUDED_CLOCK_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp new file mode 100644 index 000000000..2859a7981 --- /dev/null +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -0,0 +1,279 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp2_iface.hpp" +#include "clock_control.hpp" +#include "usrp2_regs.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/asio.hpp> //htonl and ntohl +#include <boost/math/special_functions/round.hpp> +#include <algorithm> + +using namespace uhd::usrp; + +class usrp2_dboard_iface : public dboard_iface{ +public: +    usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl); +    ~usrp2_dboard_iface(void); + +    void write_aux_dac(unit_t, int, float); +    float read_aux_adc(unit_t, int); + +    void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); +    void set_gpio_ddr(unit_t, boost::uint16_t); +    boost::uint16_t read_gpio(unit_t); + +    void write_i2c(int, const byte_vector_t &); +    byte_vector_t read_i2c(int, size_t); + +    double get_clock_rate(unit_t); +    void set_clock_enabled(unit_t, bool); +    bool get_clock_enabled(unit_t); + +    void write_spi( +        unit_t unit, +        const spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits +    ); + +    boost::uint32_t read_write_spi( +        unit_t unit, +        const spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits +    ); + +private: +    usrp2_iface::sptr _iface; +    clock_control::sptr _clk_ctrl; +    boost::uint32_t _ddr_shadow; +}; + +/*********************************************************************** + * Make Function + **********************************************************************/ +dboard_iface::sptr make_usrp2_dboard_iface( +    usrp2_iface::sptr iface, +    clock_control::sptr clk_ctrl +){ +    return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl)); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){ +    _iface = iface; +    _clk_ctrl = clk_ctrl; +    _ddr_shadow = 0; + +    //set the selection mux to use atr +    boost::uint32_t new_sels = 0x0; +    for(size_t i = 0; i < 16; i++){ +        new_sels |= FRF_GPIO_SEL_ATR << (i*2); +    } +    _iface->poke32(FR_GPIO_TX_SEL, new_sels); +    _iface->poke32(FR_GPIO_RX_SEL, new_sels); +} + +usrp2_dboard_iface::~usrp2_dboard_iface(void){ +    /* NOP */ +} + +/*********************************************************************** + * Clocks + **********************************************************************/ +double usrp2_dboard_iface::get_clock_rate(unit_t){ +    return _iface->get_master_clock_freq(); +} + +void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ +    switch(unit){ +    case UNIT_RX: +        _clk_ctrl->enable_rx_dboard_clock(enb); +        return; +    case UNIT_TX: +        _clk_ctrl->enable_tx_dboard_clock(enb); +        return; +    } +} + +/*********************************************************************** + * GPIO + **********************************************************************/ +static int unit_to_shift(dboard_iface::unit_t unit){ +    switch(unit){ +    case dboard_iface::UNIT_RX: return 0; +    case dboard_iface::UNIT_TX: return 16; +    } +    throw std::runtime_error("unknown unit type"); +} + +void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ +    _ddr_shadow = \ +        (_ddr_shadow & ~(0xffff << unit_to_shift(unit))) | +        (boost::uint32_t(value) << unit_to_shift(unit)); +    _iface->poke32(FR_GPIO_DDR, _ddr_shadow); +} + +boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){ +    return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift(unit)); +} + +void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ +    //define mapping of unit to atr regs to register address +    static const uhd::dict< +        unit_t, uhd::dict<atr_reg_t, boost::uint32_t> +    > unit_to_atr_to_addr = boost::assign::map_list_of +        (UNIT_RX, boost::assign::map_list_of +            (ATR_REG_IDLE,        FR_ATR_IDLE_RXSIDE) +            (ATR_REG_TX_ONLY,     FR_ATR_INTX_RXSIDE) +            (ATR_REG_RX_ONLY,     FR_ATR_INRX_RXSIDE) +            (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE) +        ) +        (UNIT_TX, boost::assign::map_list_of +            (ATR_REG_IDLE,        FR_ATR_IDLE_TXSIDE) +            (ATR_REG_TX_ONLY,     FR_ATR_INTX_TXSIDE) +            (ATR_REG_RX_ONLY,     FR_ATR_INRX_TXSIDE) +            (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE) +        ) +    ; +    _iface->poke16(unit_to_atr_to_addr[unit][atr], value); +} + +/*********************************************************************** + * SPI + **********************************************************************/ +/*! + * Static function to convert a unit type enum + * to an over-the-wire value for the spi device. + * \param unit the dboard interface unit type enum + * \return an over the wire representation + */ +static boost::uint8_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){ +    switch(unit){ +    case dboard_iface::UNIT_TX: return SPI_SS_TX_DB; +    case dboard_iface::UNIT_RX: return SPI_SS_RX_DB; +    } +    throw std::invalid_argument("unknown unit type"); +} + +void usrp2_dboard_iface::write_spi( +    unit_t unit, +    const spi_config_t &config, +    boost::uint32_t data, +    size_t num_bits +){ +    _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); +} + +boost::uint32_t usrp2_dboard_iface::read_write_spi( +    unit_t unit, +    const spi_config_t &config, +    boost::uint32_t data, +    size_t num_bits +){ +    return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); +} + +/*********************************************************************** + * I2C + **********************************************************************/ +void usrp2_dboard_iface::write_i2c(int i2c_addr, const byte_vector_t &buf){ +    //setup the out data +    usrp2_ctrl_data_t out_data; +    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO); +    out_data.data.i2c_args.addr = i2c_addr; +    out_data.data.i2c_args.bytes = buf.size(); + +    //limitation of i2c transaction size +    ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data)); + +    //copy in the data +    std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data); + +    //send and recv +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); +} + +dboard_iface::byte_vector_t usrp2_dboard_iface::read_i2c(int i2c_addr, size_t num_bytes){ +    //setup the out data +    usrp2_ctrl_data_t out_data; +    out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO); +    out_data.data.i2c_args.addr = i2c_addr; +    out_data.data.i2c_args.bytes = num_bytes; + +    //limitation of i2c transaction size +    ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data)); + +    //send and recv +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); +    ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); + +    //copy out the data +    byte_vector_t result(num_bytes); +    std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin()); +    return result; +} + +/*********************************************************************** + * Aux DAX/ADC + **********************************************************************/ +/*! + * Static function to convert a unit type enum + * to an over-the-wire value for the usrp2 control. + * \param unit the dboard interface unit type enum + * \return an over the wire representation + */ +static boost::uint8_t unit_to_otw(dboard_iface::unit_t unit){ +    switch(unit){ +    case dboard_iface::UNIT_TX: return USRP2_DIR_TX; +    case dboard_iface::UNIT_RX: return USRP2_DIR_RX; +    } +    throw std::invalid_argument("unknown unit type"); +} + +void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){ +    //setup the out data +    usrp2_ctrl_data_t out_data; +    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); +    out_data.data.aux_args.dir = unit_to_otw(unit); +    out_data.data.aux_args.which = which; +    out_data.data.aux_args.value = htonl(boost::math::iround(4095*value/3.3)); + +    //send and recv +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE); +} + +float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){ +    //setup the out data +    usrp2_ctrl_data_t out_data; +    out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO); +    out_data.data.aux_args.dir = unit_to_otw(unit); +    out_data.data.aux_args.which = which; + +    //send and recv +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE); +    return float(3.3*ntohl(in_data.data.aux_args.value)/4095); +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index d1515f2d5..fe74219d6 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -22,6 +22,9 @@  #include <uhd/usrp/dboard_props.hpp>  #include <uhd/utils/assert.hpp>  #include <boost/format.hpp> +#include <boost/bind.hpp> +#include <boost/asio.hpp> //htonl and ntohl +#include <iostream>  using namespace uhd;  using namespace uhd::usrp; @@ -33,7 +36,7 @@ void usrp2_impl::dboard_init(void){      //grab the dboard ids over the control line      usrp2_ctrl_data_t out_data;      out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO); -    usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);      ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE);      //extract the dboard ids an convert them @@ -41,11 +44,11 @@ void usrp2_impl::dboard_init(void){      dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id);      //create a new dboard interface and manager -    dboard_interface::sptr _dboard_interface( -        make_usrp2_dboard_interface(this) +    dboard_iface::sptr _dboard_iface( +        make_usrp2_dboard_iface(_iface, _clk_ctrl)      );      _dboard_manager = dboard_manager::make( -        rx_dboard_id, tx_dboard_id, _dboard_interface +        rx_dboard_id, tx_dboard_id, _dboard_iface      );      //load dboards @@ -81,7 +84,7 @@ void usrp2_impl::update_rx_mux_config(void){          rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0);      } -    this->poke32(FR_DSP_RX_MUX, rx_mux); +    _iface->poke32(FR_DSP_RX_MUX, rx_mux);  }  void usrp2_impl::update_tx_mux_config(void){ @@ -94,7 +97,7 @@ void usrp2_impl::update_tx_mux_config(void){          tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);      } -    this->poke32(FR_DSP_TX_MUX, tx_mux); +    _iface->poke32(FR_DSP_TX_MUX, tx_mux);  }  /*********************************************************************** diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp deleted file mode 100644 index 6dd756420..000000000 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include <uhd/types/dict.hpp> -#include <uhd/utils/assert.hpp> -#include <boost/assign/list_of.hpp> -#include <algorithm> - -using namespace uhd::usrp; - -class usrp2_dboard_interface : public dboard_interface{ -public: -    usrp2_dboard_interface(usrp2_impl *impl); -    ~usrp2_dboard_interface(void); - -    void write_aux_dac(unit_type_t, int, int); -    int read_aux_adc(unit_type_t, int); - -    void set_atr_reg(gpio_bank_t, atr_reg_t, boost::uint16_t); -    void set_gpio_ddr(gpio_bank_t, boost::uint16_t); -    boost::uint16_t read_gpio(gpio_bank_t); - -    void write_i2c(int, const byte_vector_t &); -    byte_vector_t read_i2c(int, size_t); - -    double get_rx_clock_rate(void); -    double get_tx_clock_rate(void); - -private: -    byte_vector_t transact_spi( -        spi_dev_t, spi_edge_t, const byte_vector_t &, bool -    ); - -    usrp2_impl *_impl; -    boost::uint32_t _ddr_shadow; -}; - -/*********************************************************************** - * Make Function - **********************************************************************/ -dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl){ -    return dboard_interface::sptr(new usrp2_dboard_interface(impl)); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp2_dboard_interface::usrp2_dboard_interface(usrp2_impl *impl){ -    _impl = impl; -    _ddr_shadow = 0; - -    //set the selection mux to use atr -    boost::uint32_t new_sels = 0x0; -    for(size_t i = 0; i < 16; i++){ -        new_sels |= FRF_GPIO_SEL_ATR << (i*2); -    } -    _impl->poke32(FR_GPIO_TX_SEL, new_sels); -    _impl->poke32(FR_GPIO_RX_SEL, new_sels); -} - -usrp2_dboard_interface::~usrp2_dboard_interface(void){ -    /* NOP */ -} - -/*********************************************************************** - * Clock Rates - **********************************************************************/ -double usrp2_dboard_interface::get_rx_clock_rate(void){ -    return _impl->get_master_clock_freq(); -} - -double usrp2_dboard_interface::get_tx_clock_rate(void){ -    return _impl->get_master_clock_freq(); -} - -/*********************************************************************** - * GPIO - **********************************************************************/ -static int bank_to_shift(dboard_interface::gpio_bank_t bank){ -    switch(bank){ -    case dboard_interface::GPIO_BANK_RX: return 0; -    case dboard_interface::GPIO_BANK_TX: return 16; -    } -    throw std::runtime_error("unknown gpio bank type"); -} - -void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value){ -    _ddr_shadow = \ -        (_ddr_shadow & ~(0xffff << bank_to_shift(bank))) | -        (boost::uint32_t(value) << bank_to_shift(bank)); -    _impl->poke32(FR_GPIO_DDR, _ddr_shadow); -} - -boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ -    return boost::uint16_t(_impl->peek32(FR_GPIO_IO) >> bank_to_shift(bank)); -} - -void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, atr_reg_t atr, boost::uint16_t value){ -    //define mapping of bank to atr regs to register address -    static const uhd::dict< -        gpio_bank_t, uhd::dict<atr_reg_t, boost::uint32_t> -    > bank_to_atr_to_addr = boost::assign::map_list_of -        (GPIO_BANK_RX, boost::assign::map_list_of -            (ATR_REG_IDLE,        FR_ATR_IDLE_RXSIDE) -            (ATR_REG_TX_ONLY,     FR_ATR_INTX_RXSIDE) -            (ATR_REG_RX_ONLY,     FR_ATR_INRX_RXSIDE) -            (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE) -        ) -        (GPIO_BANK_TX, boost::assign::map_list_of -            (ATR_REG_IDLE,        FR_ATR_IDLE_TXSIDE) -            (ATR_REG_TX_ONLY,     FR_ATR_INTX_TXSIDE) -            (ATR_REG_RX_ONLY,     FR_ATR_INRX_TXSIDE) -            (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE) -        ) -    ; -    _impl->poke16(bank_to_atr_to_addr[bank][atr], value); -} - -/*********************************************************************** - * SPI - **********************************************************************/ -/*! - * Static function to convert a spi dev enum - * to an over-the-wire value for the usrp2 control. - * \param dev the dboard interface spi dev enum - * \return an over the wire representation - */ -static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ -    switch(dev){ -    case uhd::usrp::dboard_interface::SPI_DEV_TX: return SPI_SS_TX_DB; -    case uhd::usrp::dboard_interface::SPI_DEV_RX: return SPI_SS_RX_DB; -    } -    throw std::invalid_argument("unknown spi device type"); -} - -/*! - * Static function to convert a spi edge enum - * to an over-the-wire value for the usrp2 control. - * \param edge the dboard interface spi edge enum - * \return an over the wire representation - */ -static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_edge_t edge){ -    switch(edge){ -    case uhd::usrp::dboard_interface::SPI_EDGE_RISE: return USRP2_CLK_EDGE_RISE; -    case uhd::usrp::dboard_interface::SPI_EDGE_FALL: return USRP2_CLK_EDGE_FALL; -    } -    throw std::invalid_argument("unknown spi edge type"); -} - -dboard_interface::byte_vector_t usrp2_dboard_interface::transact_spi( -    spi_dev_t dev, -    spi_edge_t edge, -    const byte_vector_t &buf, -    bool readback -){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); -    out_data.data.spi_args.dev = spi_dev_to_otw(dev); -    out_data.data.spi_args.edge = spi_edge_to_otw(edge); -    out_data.data.spi_args.readback = (readback)? 1 : 0; -    out_data.data.spi_args.bytes = buf.size(); - -    //limitation of spi transaction size -    ASSERT_THROW(buf.size() <= sizeof(out_data.data.spi_args.data)); - -    //copy in the data -    std::copy(buf.begin(), buf.end(), out_data.data.spi_args.data); - -    //send and recv -    usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); -    ASSERT_THROW(in_data.data.spi_args.bytes == buf.size()); - -    //copy out the data -    byte_vector_t result(buf.size()); -    std::copy(in_data.data.spi_args.data, in_data.data.spi_args.data + buf.size(), result.begin()); -    return result; -} - -/*********************************************************************** - * I2C - **********************************************************************/ -void usrp2_dboard_interface::write_i2c(int i2c_addr, const byte_vector_t &buf){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO); -    out_data.data.i2c_args.addr = i2c_addr; -    out_data.data.i2c_args.bytes = buf.size(); - -    //limitation of i2c transaction size -    ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data)); - -    //copy in the data -    std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data); - -    //send and recv -    usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); -} - -dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, size_t num_bytes){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO); -    out_data.data.i2c_args.addr = i2c_addr; -    out_data.data.i2c_args.bytes = num_bytes; - -    //limitation of i2c transaction size -    ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data)); - -    //send and recv -    usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); -    ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); - -    //copy out the data -    byte_vector_t result(num_bytes); -    std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin()); -    return result; -} - -/*********************************************************************** - * Aux DAX/ADC - **********************************************************************/ -/*! - * Static function to convert a unit type enum - * to an over-the-wire value for the usrp2 control. - * \param unit the dboard interface unit type enum - * \return an over the wire representation - */ -static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ -    switch(unit){ -    case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; -    case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; -    } -    throw std::invalid_argument("unknown unit type type"); -} - -void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int value){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); -    out_data.data.aux_args.dir = spi_dev_to_otw(unit); -    out_data.data.aux_args.which = which; -    out_data.data.aux_args.value = htonl(value); - -    //send and recv -    usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE); -} - -int usrp2_dboard_interface::read_aux_adc(dboard_interface::unit_type_t unit, int which){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO); -    out_data.data.aux_args.dir = spi_dev_to_otw(unit); -    out_data.data.aux_args.which = which; - -    //send and recv -    usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE); -    return ntohl(in_data.data.aux_args.value); -} diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 92b55d029..204277ba7 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -20,6 +20,7 @@  #include <uhd/usrp/dsp_props.hpp>  #include <uhd/utils/assert.hpp>  #include <boost/format.hpp> +#include <boost/bind.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/math/special_functions/round.hpp> @@ -39,7 +40,8 @@ template <class T> T log2(T num){   * DDC Helper Methods   **********************************************************************/  static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){ -    double scale_factor = std::pow(2.0, 32); +    ASSERT_THROW(std::abs(freq) < clock_freq/2.0); +    static const double scale_factor = std::pow(2.0, 32);      //calculate the freq register word      boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor); @@ -82,11 +84,11 @@ void usrp2_impl::init_ddc_config(void){  void usrp2_impl::update_ddc_config(void){      //set the decimation -    this->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim); +    _iface->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);      //set the scaling      static const boost::int16_t default_rx_scale_iq = 1024; -    this->poke32(FR_DSP_RX_SCALE_IQ, +    _iface->poke32(FR_DSP_RX_SCALE_IQ,          calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)      );  } @@ -123,12 +125,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){      case DSP_PROP_FREQ_SHIFT:{              double new_freq = val.as<double>(); -            ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); -            ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); -            _ddc_freq = new_freq; //shadow -            this->poke32(FR_DSP_RX_FREQ, -                calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq()) +            _iface->poke32(FR_DSP_RX_FREQ, +                calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())              ); +            _ddc_freq = new_freq; //shadow          }          return; @@ -170,10 +170,10 @@ void usrp2_impl::update_duc_config(void){      boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));      //set the interpolation -    this->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim); +    _iface->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);      //set the scaling -    this->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale)); +    _iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));  }  /*********************************************************************** @@ -208,12 +208,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){      case DSP_PROP_FREQ_SHIFT:{              double new_freq = val.as<double>(); -            ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); -            ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); -            _duc_freq = new_freq; //shadow -            this->poke32(FR_DSP_TX_FREQ, -                calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq()) +            _iface->poke32(FR_DSP_TX_FREQ, +                calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())              ); +            _duc_freq = new_freq; //shadow          }          return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 019f3b931..b600a2a70 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -110,10 +110,11 @@ typedef struct{          } dboard_ids;          struct {              _SINS_ uint8_t dev; -            _SINS_ uint8_t edge; +            _SINS_ uint8_t miso_edge; +            _SINS_ uint8_t mosi_edge;              _SINS_ uint8_t readback; -            _SINS_ uint8_t bytes; -            _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; +            _SINS_ uint32_t data; +            _SINS_ uint8_t num_bits;          } spi_args;          struct {              _SINS_ uint8_t addr; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index a58e32619..367a1d9fb 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -15,9 +15,11 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <complex> -#include <boost/format.hpp>  #include "usrp2_impl.hpp" +#include <uhd/transport/convert_types.hpp> +#include <boost/format.hpp> +#include <boost/asio.hpp> //htonl and ntohl +#include <iostream>  using namespace uhd;  using namespace uhd::usrp; @@ -25,101 +27,26 @@ using namespace uhd::transport;  namespace asio = boost::asio;  /*********************************************************************** - * Constants - **********************************************************************/ -typedef std::complex<float>          fc32_t; -typedef std::complex<boost::int16_t> sc16_t; - -static const float shorts_per_float = float(1 << 15); -static const float floats_per_short = float(1.0/shorts_per_float); - -/***********************************************************************   * Helper Functions   **********************************************************************/  void usrp2_impl::io_init(void){ +    //setup otw type +    _otw_type.width = 16; +    _otw_type.shift = 0; +    _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; +      //initially empty copy buffer      _rx_copy_buff = asio::buffer("", 0);      //send a small data packet so the usrp2 knows the udp source port      //and the maximum number of lines (32 bit words) per packet +    managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();      boost::uint32_t data[2] = {          htonl(USRP2_INVALID_VRT_HEADER),          htonl(_max_rx_samples_per_packet)      }; -    _data_transport->send(asio::buffer(&data, sizeof(data))); -} - -#define unrolled_loop(__inst, __len){ \ -    size_t __i = 0; \ -    for(; __i < (__len & ~0x3); __i+= 4){ \ -        __inst(__i+0); __inst(__i+1); \ -        __inst(__i+2); __inst(__i+3); \ -    } \ -    for(; __i < __len; __i++){ \ -        __inst(__i); \ -    } \ -} - -// set a boolean flag that indicates the endianess -#ifdef HAVE_BIG_ENDIAN -static const bool is_big_endian = true; -#else -static const bool is_big_endian = false; -#endif - -static inline void host_floats_to_usrp2_items( -    boost::uint32_t *usrp2_items, -    const fc32_t *host_floats, -    size_t num_samps -){ -    #define host_floats_to_usrp2_items_i(i){ \ -        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ -        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ -        usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ -    } -    unrolled_loop(host_floats_to_usrp2_items_i, num_samps); -} - -static inline void usrp2_items_to_host_floats( -    fc32_t *host_floats, -    const boost::uint32_t *usrp2_items, -    size_t num_samps -){ -    #define usrp2_items_to_host_floats_i(i){ \ -        boost::uint32_t item = ntohl(usrp2_items[i]); \ -        boost::int16_t real = boost::uint16_t(item >> 16); \ -        boost::int16_t imag = boost::uint16_t(item >> 0); \ -        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ -    } -    unrolled_loop(usrp2_items_to_host_floats_i, num_samps); -} - -static inline void host_items_to_usrp2_items( -    boost::uint32_t *usrp2_items, -    const boost::uint32_t *host_items, -    size_t num_samps -){ -    #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) -    if (is_big_endian){ -        std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); -    } -    else{ -        unrolled_loop(host_items_to_usrp2_items_i, num_samps); -    } -} - -static inline void usrp2_items_to_host_items( -    boost::uint32_t *host_items, -    const boost::uint32_t *usrp2_items, -    size_t num_samps -){ -    #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) -    if (is_big_endian){ -        std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); -    } -    else{ -        unrolled_loop(usrp2_items_to_host_items_i, num_samps); -    } +    memcpy(send_buff->cast<void*>(), data, sizeof(data)); +    send_buff->done(sizeof(data));  }  /*********************************************************************** @@ -127,15 +54,15 @@ static inline void usrp2_items_to_host_items(   **********************************************************************/  void usrp2_impl::recv_raw(rx_metadata_t &metadata){      //do a receive -    _rx_smart_buff = _data_transport->recv(); +    _rx_smart_buff = _data_transport->get_recv_buff();      //unpack the vrt header -    size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t); +    size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t);      if (num_packet_words32 == 0){          _rx_copy_buff = boost::asio::buffer("", 0);          return; //must exit here after setting the buffer      } -    const boost::uint32_t *vrt_hdr = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get()); +    const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>();      size_t num_header_words32_out, num_payload_words32_out, packet_count_out;      try{          vrt::unpack( @@ -144,7 +71,8 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){              num_header_words32_out,  //output              num_payload_words32_out, //output              num_packet_words32,      //input -            packet_count_out         //output +            packet_count_out,        //output +            get_master_clock_freq()          );      }catch(const std::exception &e){          std::cerr << "bad vrt header: " << e.what() << std::endl; @@ -176,10 +104,12 @@ size_t usrp2_impl::send(  ){      tx_metadata_t metadata = metadata_; //rw copy to change later -    boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; -    size_t num_samps = std::min( +    transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); +    boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>(); +    size_t num_samps = std::min(std::min(          asio::buffer_size(buff)/io_type.size, -        size_t(_max_tx_samples_per_packet) +        size_t(_max_tx_samples_per_packet)), +        send_buff->size()/io_type.size      );      //kill the end of burst flag if this is a fragment @@ -196,25 +126,21 @@ size_t usrp2_impl::send(          num_header_words32,  //output          num_samps,           //input          num_packet_words32,  //output -        packet_count         //input +        packet_count,        //input +        get_master_clock_freq()      );      boost::uint32_t *items = tx_mem + num_header_words32; //offset for data -    //copy the samples into the send buffer -    switch(io_type.tid){ -    case io_type_t::COMPLEX_FLOAT32: -        host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); -        break; -    case io_type_t::COMPLEX_INT16: -        host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); -        break; -    default: -        throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid)); -    } +    //copy-convert the samples into the send buffer +    convert_io_type_to_otw_type( +        asio::buffer_cast<const void*>(buff), io_type, +        (void*)items, _otw_type, +        num_samps +    );      //send and return number of samples -    _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t))); +    send_buff->done(num_packet_words32*sizeof(boost::uint32_t));      return num_samps;  } @@ -251,17 +177,12 @@ size_t usrp2_impl::recv(      metadata.fragment_offset = _fragment_offset_in_samps;      _fragment_offset_in_samps += num_samps; //set for next time -    //copy the samples from the recv buffer -    switch(io_type.tid){ -    case io_type_t::COMPLEX_FLOAT32: -        usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); -        break; -    case io_type_t::COMPLEX_INT16: -        usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); -        break; -    default: -        throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid)); -    } +    //copy-convert the samples from the recv buffer +    convert_otw_type_to_io_type( +        (const void*)items, _otw_type, +        asio::buffer_cast<void*>(buff), io_type, +        num_samps +    );      //update the rx copy buffer to reflect the bytes copied      _rx_copy_buff = asio::buffer( diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 94ab88a6b..d7728238c 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -17,10 +17,14 @@  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include "ad9777_regs.hpp"  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/mac_addr.hpp>  #include <uhd/types/dict.hpp> +#include <boost/bind.hpp> +#include <boost/asio.hpp> //htonl and ntohl +#include <boost/assign/list_of.hpp>  using namespace uhd;  using namespace uhd::usrp; @@ -34,9 +38,31 @@ void usrp2_impl::mboard_init(void){          boost::bind(&usrp2_impl::mboard_set, this, _1, _2)      ); -    //set the time on the usrp2 as close as possible to the system utc time -    boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time()); -    set_time_spec(time_spec_t(now, get_master_clock_freq()), true); +    _clk_ctrl = clock_control::make_ad9510(_iface); + +    //setup the ad9777 dac +    ad9777_regs_t ad9777_regs; +    ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; +    ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; +    ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; +    ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; +    ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; +    ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; +    //I dac values +    ad9777_regs.idac_fine_gain_adjust = 0; +    ad9777_regs.idac_coarse_gain_adjust = 0xf; +    ad9777_regs.idac_offset_adjust_lsb = 0; +    ad9777_regs.idac_offset_adjust_msb = 0; +    //Q dac values +    ad9777_regs.qdac_fine_gain_adjust = 0; +    ad9777_regs.qdac_coarse_gain_adjust = 0xf; +    ad9777_regs.qdac_offset_adjust_lsb = 0; +    ad9777_regs.qdac_offset_adjust_msb = 0; +    //write all regs +    for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ +        boost::uint16_t data = ad9777_regs.get_write_reg(addr); +        _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/); +    }  }  void usrp2_impl::init_clock_config(void){ @@ -67,19 +93,28 @@ void usrp2_impl::update_clock_config(void){      }      //set the pps flags -    this->poke32(FR_TIME64_FLAGS, pps_flags); +    _iface->poke32(FR_TIME64_FLAGS, pps_flags); + +    //clock source ref 10mhz +    switch(_clock_config.ref_source){ +    case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break; +    case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break; +    case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break; +    } -    //TODO clock source ref 10mhz (spi ad9510) +    //clock source ref 10mhz +    bool use_external = _clock_config.ref_source != clock_config_t::REF_INT; +    _clk_ctrl->enable_external_ref(use_external);  }  void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){      //set ticks and seconds -    this->poke32(FR_TIME64_SECS, time_spec.secs); -    this->poke32(FR_TIME64_TICKS, time_spec.ticks); +    _iface->poke32(FR_TIME64_SECS, time_spec.secs); +    _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));      //set the register to latch it all in      boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS; -    this->poke32(FR_TIME64_IMM, imm_flags); +    _iface->poke32(FR_TIME64_IMM, imm_flags);  }  void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ @@ -88,7 +123,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO);      out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0;      out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); -    out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks); +    out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq()));      //set these to defaults, then change in the switch statement      out_data.data.stream_cmd.continuous = 0; @@ -115,7 +150,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      }      //send and recv -    usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);      ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);  } @@ -134,7 +169,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){              out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO);              //send and recv -            usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +            usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);              ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);              //extract the address @@ -148,7 +183,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){              out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);              //send and recv -            usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +            usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);              ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);              //extract the address @@ -190,10 +225,6 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, "");          return; -    case MBOARD_PROP_CLOCK_RATE: -        val = double(get_master_clock_freq()); -        return; -      case MBOARD_PROP_RX_DSP:          ASSERT_THROW(name == "");          val = _rx_dsp_proxy->get_link(); @@ -236,7 +267,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){              std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr);              //send and recv -            usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +            usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);              ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);              return;          } @@ -248,7 +279,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){              out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_ulong());              //send and recv -            usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +            usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);              ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);              return;          } diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp new file mode 100644 index 000000000..5c84fd8d3 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -0,0 +1,168 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp2_iface.hpp" +#include <uhd/utils/assert.hpp> +#include <uhd/types/dict.hpp> +#include <boost/thread.hpp> +#include <boost/asio.hpp> //used for htonl and ntohl +#include <boost/assign/list_of.hpp> +#include <stdexcept> + +using namespace uhd; +using namespace uhd::usrp; + +class usrp2_iface_impl : public usrp2_iface{ +public: +/*********************************************************************** + * Structors + **********************************************************************/ +    usrp2_iface_impl(transport::udp_simple::sptr ctrl_transport){ +        _ctrl_transport = ctrl_transport; +    } + +    ~usrp2_iface_impl(void){ +        /* NOP */ +    } + +/*********************************************************************** + * Peek and Poke + **********************************************************************/ +    void poke32(boost::uint32_t addr, boost::uint32_t data){ +        return this->poke<boost::uint32_t>(addr, data); +    } + +    boost::uint32_t peek32(boost::uint32_t addr){ +        return this->peek<boost::uint32_t>(addr); +    } + +    void poke16(boost::uint32_t addr, boost::uint16_t data){ +        return this->poke<boost::uint16_t>(addr, data); +    } + +    boost::uint16_t peek16(boost::uint32_t addr){ +        return this->peek<boost::uint16_t>(addr); +    } + +/*********************************************************************** + * SPI + **********************************************************************/ +    boost::uint32_t transact_spi( +        int which_slave, +        const spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits, +        bool readback +    ){ +        static const uhd::dict<spi_config_t::edge_t, int> spi_edge_to_otw = boost::assign::map_list_of +            (spi_config_t::EDGE_RISE, USRP2_CLK_EDGE_RISE) +            (spi_config_t::EDGE_FALL, USRP2_CLK_EDGE_FALL) +        ; + +        //setup the out data +        usrp2_ctrl_data_t out_data; +        out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); +        out_data.data.spi_args.dev = which_slave; +        out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge]; +        out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge]; +        out_data.data.spi_args.readback = (readback)? 1 : 0; +        out_data.data.spi_args.num_bits = num_bits; +        out_data.data.spi_args.data = htonl(data); + +        //send and recv +        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); +        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); + +        return ntohl(out_data.data.spi_args.data); +    } + +/*********************************************************************** + * Send/Recv over control + **********************************************************************/ +    usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){ +        boost::mutex::scoped_lock lock(_ctrl_mutex); + +        //fill in the seq number and send +        usrp2_ctrl_data_t out_copy = out_data; +        out_copy.seq = htonl(++_ctrl_seq_num); +        _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); + +        //loop until we get the packet or timeout +        while(true){ +            usrp2_ctrl_data_t in_data; +            size_t len = _ctrl_transport->recv(boost::asio::buffer(&in_data, sizeof(in_data))); +            if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){ +                return in_data; +            } +            if (len == 0) break; //timeout +            //didnt get seq or bad packet, continue looking... +        } +        throw std::runtime_error("usrp2 no control response"); +    } + +/*********************************************************************** + * Master Clock! Ahhhhh + **********************************************************************/ +    double get_master_clock_freq(void){ +        return 100e6; +    } + +private: +    //this lovely lady makes it all possible +    transport::udp_simple::sptr _ctrl_transport; + +    //used in send/recv +    boost::mutex _ctrl_mutex; +    boost::uint32_t _ctrl_seq_num; + +/*********************************************************************** + * Private Templated Peek and Poke + **********************************************************************/ +    template <class T> void poke(boost::uint32_t addr, T data){ +        //setup the out data +        usrp2_ctrl_data_t out_data; +        out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO); +        out_data.data.poke_args.addr = htonl(addr); +        out_data.data.poke_args.data = htonl(boost::uint32_t(data)); +        out_data.data.poke_args.num_bytes = sizeof(T); + +        //send and recv +        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); +        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); +    } + +    template <class T> T peek(boost::uint32_t addr){ +        //setup the out data +        usrp2_ctrl_data_t out_data; +        out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); +        out_data.data.poke_args.addr = htonl(addr); +        out_data.data.poke_args.num_bytes = sizeof(T); + +        //send and recv +        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); +        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); +        return T(ntohl(out_data.data.poke_args.data)); +    } + +}; + +/*********************************************************************** + * Public make function for usrp2 interface + **********************************************************************/ +usrp2_iface::sptr usrp2_iface::make(transport::udp_simple::sptr ctrl_transport){ +    return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport)); +} diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp new file mode 100644 index 000000000..1298d87f1 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -0,0 +1,103 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_USRP2_IFACE_HPP +#define INCLUDED_USRP2_IFACE_HPP + +#include <uhd/transport/udp_simple.hpp> +#include <uhd/usrp/dboard_iface.hpp> //spi config +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <boost/cstdint.hpp> +#include "fw_common.h" + +/*! + * The usrp2 interface class: + * Provides a set of functions to implementation layer. + * Including spi, peek, poke, control... + */ +class usrp2_iface : boost::noncopyable{ +public: +    typedef boost::shared_ptr<usrp2_iface> sptr; + +    /*! +     * Make a new usrp2 interface with the control transport. +     * \param ctrl_transport the udp transport object +     * \return a new usrp2 interface object +     */ +    static sptr make(uhd::transport::udp_simple::sptr ctrl_transport); + +    /*! +     * Perform a control transaction. +     * \param data a control data struct +     * \return the result control data +     */ +    virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0; + +    /*! +     * Write a register (32 bits) +     * \param addr the address +     * \param data the 32bit data +     */ +    virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0; + +    /*! +     * Read a register (32 bits) +     * \param addr the address +     * \return the 32bit data +     */ +    virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; + +    /*! +     * Write a register (16 bits) +     * \param addr the address +     * \param data the 16bit data +     */ +    virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; + +    /*! +     * Read a register (16 bits) +     * \param addr the address +     * \return the 16bit data +     */ +    virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; + +    /*! +     * Perform an spi transaction. +     * \param which_slave the slave device number +     * \param config spi config args +     * \param data the bits to write +     * \param num_bits how many bits in data +     * \param readback true to readback a value +     * \return spi data if readback set +     */ +    virtual boost::uint32_t transact_spi( +        int which_slave, +        const uhd::usrp::spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits, +        bool readback +    ) = 0; + +    /*! +     * Get the master clock frequency. +     * \return the frequency in Hz +     */ +    virtual double get_master_clock_freq(void) = 0; +}; + +#endif /* INCLUDED_USRP2_IFACE_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index a7be2da8c..3bdc5bd02 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -15,15 +15,18 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include "usrp2_impl.hpp"  #include <uhd/transport/if_addrs.hpp> +#include <uhd/transport/udp_simple.hpp>  #include <uhd/usrp/device_props.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> +#include <boost/assign/list_of.hpp>  #include <boost/format.hpp>  #include <boost/foreach.hpp>  #include <boost/bind.hpp> +#include <boost/asio.hpp> //htonl and ntohl  #include <iostream> -#include "usrp2_impl.hpp"  using namespace uhd;  using namespace uhd::usrp; @@ -60,7 +63,6 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){      }      //create a udp transport to communicate -    //TODO if an addr is not provided, search all interfaces?      std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);      udp_simple::sptr udp_transport = udp_simple::make_broadcast(          hint["addr"], ctrl_port @@ -127,9 +129,11 @@ usrp2_impl::usrp2_impl(      udp_simple::sptr ctrl_transport,      udp_zero_copy::sptr data_transport  ){ -    _ctrl_transport = ctrl_transport;      _data_transport = data_transport; +    //make a new interface for usrp2 stuff +    _iface = usrp2_iface::make(ctrl_transport); +      //load the allowed decim/interp rates      //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)      _allowed_decim_and_interp_rates.clear(); @@ -168,80 +172,6 @@ usrp2_impl::~usrp2_impl(void){  }  /*********************************************************************** - * Misc Access Methods - **********************************************************************/ -double usrp2_impl::get_master_clock_freq(void){ -    return 100e6; -} - -template <class T> void impl_poke(usrp2_impl *impl, boost::uint32_t addr, T data){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO); -    out_data.data.poke_args.addr = htonl(addr); -    out_data.data.poke_args.data = htonl(boost::uint32_t(data)); -    out_data.data.poke_args.num_bytes = sizeof(T); - -    //send and recv -    usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); -} - -template <class T> T impl_peek(usrp2_impl *impl, boost::uint32_t addr){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); -    out_data.data.poke_args.addr = htonl(addr); -    out_data.data.poke_args.num_bytes = sizeof(T); - -    //send and recv -    usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); -    return T(ntohl(out_data.data.poke_args.data)); -} - - -void usrp2_impl::poke32(boost::uint32_t addr, boost::uint32_t data){ -    return impl_poke<boost::uint32_t>(this, addr, data); -} - -boost::uint32_t usrp2_impl::peek32(boost::uint32_t addr){ -    return impl_peek<boost::uint32_t>(this, addr); -} - -void usrp2_impl::poke16(boost::uint32_t addr, boost::uint16_t data){ -    return impl_poke<boost::uint16_t>(this, addr, data); -} - -boost::uint16_t usrp2_impl::peek16(boost::uint32_t addr){ -    return impl_peek<boost::uint16_t>(this, addr); -} - -/*********************************************************************** - * Control Send/Recv - **********************************************************************/ -usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){ -    boost::mutex::scoped_lock lock(_ctrl_mutex); - -    //fill in the seq number and send -    usrp2_ctrl_data_t out_copy = out_data; -    out_copy.seq = htonl(++_ctrl_seq_num); -    _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); - -    //loop until we get the packet or timeout -    while(true){ -        usrp2_ctrl_data_t in_data; -        size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data))); -        if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){ -            return in_data; -        } -        if (len == 0) break; //timeout -        //didnt get seq or bad packet, continue looking... -    } -    throw std::runtime_error("usrp2 no control response"); -} - -/***********************************************************************   * Device Properties   **********************************************************************/  void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index baa6530b8..dbcee367b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -18,29 +18,29 @@  #ifndef INCLUDED_USRP2_IMPL_HPP  #define INCLUDED_USRP2_IMPL_HPP +#include "usrp2_iface.hpp" +#include "clock_control.hpp"  #include <uhd/usrp/usrp2.hpp>  #include <uhd/types/dict.hpp> +#include <uhd/types/otw_type.hpp>  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/clock_config.hpp> -#include <boost/asio.hpp> -#include <boost/thread.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp> -#include <boost/assign/list_of.hpp>  #include <uhd/transport/vrt.hpp> -#include <uhd/transport/udp_simple.hpp>  #include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/usrp/dboard_manager.hpp> -#include "fw_common.h" - -class usrp2_impl; //dummy class declaration  /*!   * Make a usrp2 dboard interface. - * \param impl a pointer to the usrp2 impl object + * \param iface the usrp2 interface object + * \param clk_ctrl the clock control object   * \return a sptr to a new dboard interface   */ -uhd::usrp::dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl); +uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( +    usrp2_iface::sptr iface, +    clock_control::sptr clk_ctrl +);  /*!   * Simple wax obj proxy class: @@ -99,28 +99,23 @@ public:      ~usrp2_impl(void); -    //performs a control transaction -    usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &); - -    //peek and poke registers -    void poke32(boost::uint32_t addr, boost::uint32_t data); -    boost::uint32_t peek32(boost::uint32_t addr); - -    void poke16(boost::uint32_t addr, boost::uint16_t data); -    boost::uint16_t peek16(boost::uint32_t addr); - -    //misc access methods -    double get_master_clock_freq(void); -      //the io interface      size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);      size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);  private: +    double get_master_clock_freq(void){ +        return _iface->get_master_clock_freq(); +    } +      //device properties interface      void get(const wax::obj &, wax::obj &);      void set(const wax::obj &, const wax::obj &); +    //interfaces +    clock_control::sptr _clk_ctrl; +    usrp2_iface::sptr _iface; +      //the raw io interface (samples are in the usrp2 native format)      void recv_raw(uhd::rx_metadata_t &);      uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq; @@ -136,19 +131,15 @@ private:          (_mtu - _hdrs)/sizeof(boost::uint32_t) -          uhd::transport::vrt::max_header_words32      ; -    uhd::transport::smart_buffer::sptr _rx_smart_buff; +    uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;      boost::asio::const_buffer _rx_copy_buff;      size_t _fragment_offset_in_samps; +    uhd::otw_type_t _otw_type;      void io_init(void);      //udp transports for control and data -    uhd::transport::udp_simple::sptr _ctrl_transport;      uhd::transport::udp_zero_copy::sptr _data_transport; -    //private vars for dealing with send/recv control -    boost::uint32_t _ctrl_seq_num; -    boost::mutex _ctrl_mutex; -      //methods and shadows for clock configuration      uhd::clock_config_t _clock_config;      void init_clock_config(void); diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 77d9f4ad9..0e2a18756 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -62,6 +62,11 @@  #define SPI_SS_TX_DB   128  ///////////////////////////////////////////////// +// Misc Control +//////////////////////////////////////////////// +#define FR_CLOCK_CONTROL _SR_ADDR(0) + +/////////////////////////////////////////////////  // VITA49 64 bit time (write only)  ////////////////////////////////////////////////    /*! | 
