diff options
Diffstat (limited to 'host/lib/usrp/usrp2')
| -rw-r--r-- | host/lib/usrp/usrp2/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.cpp | 13 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.hpp | 7 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/codec_ctrl.cpp | 14 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/codec_ctrl.hpp | 7 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/dboard_iface.cpp | 48 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 16 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 57 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp | 244 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp | 47 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.cpp | 77 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.hpp | 3 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 70 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 19 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.hpp | 4 | 
15 files changed, 551 insertions, 78 deletions
| diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 10f7407b0..da39d9df1 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2011 Ettus Research LLC +# Copyright 2011-2012 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 @@ -32,5 +32,6 @@ IF(ENABLE_USRP2)          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_fifo_ctrl.cpp      )  ENDIF(ENABLE_USRP2) diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index b2912c70c..0ae3b0bd8 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 Ettus Research LLC  //  // This program is free software: you can redistribute it and/or modify  // it under the terms of the GNU General Public License as published by @@ -35,8 +35,9 @@ static const bool enb_test_clk = false;   */  class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{  public: -    usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){ +    usrp2_clock_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){          _iface = iface; +        _spiface = spiface;          clk_regs = usrp2_clk_regs_t(_iface->get_rev());          _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; @@ -331,7 +332,7 @@ private:       */      void write_reg(boost::uint8_t addr){          boost::uint32_t data = _ad9510_regs.get_write_reg(addr); -        _iface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24); +        _spiface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24);      }      /*! @@ -377,7 +378,7 @@ private:      }      usrp2_iface::sptr _iface; - +    uhd::spi_iface::sptr _spiface;      usrp2_clk_regs_t clk_regs;      ad9510_regs_t _ad9510_regs;  }; @@ -385,6 +386,6 @@ private:  /***********************************************************************   * Public make function for the ad9510 clock control   **********************************************************************/ -usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_clock_ctrl_impl(iface)); +usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ +    return sptr(new usrp2_clock_ctrl_impl(iface, spiface));  } diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 9ccbc959e..067e1e35d 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2012 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 @@ -29,10 +29,11 @@ public:      /*!       * Make a clock config for the ad9510 ic. -     * \param _iface a pointer to the usrp2 interface object +     * \param iface a pointer to the usrp2 interface object +     * \param spiface the interface to spi       * \return a new clock control object       */ -    static sptr make(usrp2_iface::sptr iface); +    static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);      /*!       * Get the master clock frequency for the fpga. diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 06bf83b15..b53c4d9df 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -32,8 +32,9 @@ using namespace uhd;   */  class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{  public: -    usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){ +    usrp2_codec_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){          _iface = iface; +        _spiface = spiface;          //setup the ad9777 dac          _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; @@ -189,11 +190,12 @@ private:      ad9777_regs_t _ad9777_regs;      ads62p44_regs_t _ads62p44_regs;      usrp2_iface::sptr _iface; +    uhd::spi_iface::sptr _spiface;      void send_ad9777_reg(boost::uint8_t addr){          boost::uint16_t reg = _ad9777_regs.get_write_reg(addr);          UHD_LOGV(always) << "send_ad9777_reg: " << std::hex << reg << std::endl; -        _iface->write_spi( +        _spiface->write_spi(              SPI_SS_AD9777, spi_config_t::EDGE_RISE,              reg, 16          ); @@ -201,7 +203,7 @@ private:      void send_ads62p44_reg(boost::uint8_t addr) {          boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr); -        _iface->write_spi( +        _spiface->write_spi(              SPI_SS_ADS62P44, spi_config_t::EDGE_FALL,              reg, 16          ); @@ -211,6 +213,6 @@ private:  /***********************************************************************   * Public make function for the usrp2 codec control   **********************************************************************/ -usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_codec_ctrl_impl(iface)); +usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ +    return sptr(new usrp2_codec_ctrl_impl(iface, spiface));  } diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index ca300e2b1..b0d815be2 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 Ettus Research LLC  //  // This program is free software: you can redistribute it and/or modify  // it under the terms of the GNU General Public License as published by @@ -28,10 +28,11 @@ public:      /*!       * Make a codec control for the DAC and ADC. -     * \param _iface a pointer to the usrp2 interface object +     * \param iface a pointer to the usrp2 interface object +     * \param spiface the interface to spi       * \return a new codec control object       */ -    static sptr make(usrp2_iface::sptr iface); +    static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);      /*!       * Set the modulation mode for the DAC. diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index bc510c8a1..edd9ef242 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 Ettus Research LLC  //  // This program is free software: you can redistribute it and/or modify  // it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@  //  #include "gpio_core_200.hpp" -#include "usrp2_iface.hpp" +#include <uhd/types/serial.hpp>  #include "clock_ctrl.hpp"  #include "usrp2_regs.hpp" //wishbone address constants  #include <uhd/usrp/dboard_iface.hpp> @@ -35,7 +35,12 @@ using namespace boost::assign;  class usrp2_dboard_iface : public dboard_iface{  public: -    usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl); +    usrp2_dboard_iface( +        wb_iface::sptr wb_iface, +        uhd::i2c_iface::sptr i2c_iface, +        uhd::spi_iface::sptr spi_iface, +        usrp2_clock_ctrl::sptr clock_ctrl +    );      ~usrp2_dboard_iface(void);      special_props_t get_special_props(void){ @@ -79,7 +84,8 @@ public:      );  private: -    usrp2_iface::sptr _iface; +    uhd::i2c_iface::sptr _i2c_iface; +    uhd::spi_iface::sptr _spi_iface;      usrp2_clock_ctrl::sptr _clock_ctrl;      gpio_core_200::sptr _gpio; @@ -92,22 +98,28 @@ private:   * Make Function   **********************************************************************/  dboard_iface::sptr make_usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clock_ctrl  ){ -    return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl)); +    return dboard_iface::sptr(new usrp2_dboard_iface(wb_iface, i2c_iface, spi_iface, clock_ctrl));  }  /***********************************************************************   * Structors   **********************************************************************/  usrp2_dboard_iface::usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clock_ctrl -){ -    _iface = iface; -    _clock_ctrl = clock_ctrl; -    _gpio = gpio_core_200::make(_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB); +): +    _i2c_iface(i2c_iface), +    _spi_iface(spi_iface), +    _clock_ctrl(clock_ctrl) +{ +    _gpio = gpio_core_200::make(wb_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB);      //reset the aux dacs      _dac_regs[UNIT_RX] = ad5623_regs_t(); @@ -202,7 +214,7 @@ void usrp2_dboard_iface::write_spi(      boost::uint32_t data,      size_t num_bits  ){ -    _iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits); +    _spi_iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits);  }  boost::uint32_t usrp2_dboard_iface::read_write_spi( @@ -211,18 +223,18 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(      boost::uint32_t data,      size_t num_bits  ){ -    return _iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits); +    return _spi_iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits);  }  /***********************************************************************   * I2C   **********************************************************************/  void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ -    return _iface->write_i2c(addr, bytes); +    return _i2c_iface->write_i2c(addr, bytes);  }  byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ -    return _iface->read_i2c(addr, num_bytes); +    return _i2c_iface->read_i2c(addr, num_bytes);  }  /*********************************************************************** @@ -233,7 +245,7 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){          (UNIT_RX, SPI_SS_RX_DAC)          (UNIT_TX, SPI_SS_TX_DAC)      ; -    _iface->write_spi( +    _spi_iface->write_spi(          unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,           _dac_regs[unit].get_reg(), 24      ); @@ -281,11 +293,11 @@ double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){      } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn      //write and read spi -    _iface->write_spi( +    _spi_iface->write_spi(          unit_to_spi_adc[unit], config,          ad7922_regs.get_reg(), 16      ); -    ad7922_regs.set_reg(boost::uint16_t(_iface->read_spi( +    ad7922_regs.set_reg(boost::uint16_t(_spi_iface->read_spi(          unit_to_spi_adc[unit], config,          ad7922_regs.get_reg(), 16      ))); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 0babf7445..acd5d1f3a 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -30,13 +30,20 @@ extern "C" {  #endif  //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 9 -#define USRP2_FW_COMPAT_NUM 11 +#define USRP2_FPGA_COMPAT_NUM 10 +#define USRP2_FW_COMPAT_NUM 12  #define USRP2_FW_VER_MINOR 2  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 +typedef struct{ +    uint32_t sequence; +    uint32_t vrt_hdr; +    uint32_t ip_addr; +    uint32_t udp_port; +} usrp2_stream_ctrl_t; +  // udp ports for the usrp2 communication  // Dynamic and/or private ports: 49152-65535  #define USRP2_UDP_CTRL_PORT 49152 @@ -44,6 +51,7 @@ extern "C" {  #define USRP2_UDP_RX_DSP0_PORT 49156  #define USRP2_UDP_TX_DSP0_PORT 49157  #define USRP2_UDP_RX_DSP1_PORT 49158 +#define USRP2_UDP_FIFO_CRTL_PORT 49159  #define USRP2_UDP_UART_BASE_PORT 49170  #define USRP2_UDP_UART_GPS_PORT 49172 @@ -65,6 +73,8 @@ extern "C" {  ////////////////////////////////////////////////////////////////////////  #define USRP2_EE_MBOARD_REV      0x00 //2 bytes, little-endian (historic, don't blame me)  #define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_GATEWAY  0x38 //uint32, big-endian +#define USRP2_EE_MBOARD_SUBNET   0x08 //uint32, big-endian  #define USRP2_EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian  #define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7 diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index d32ffb62c..ea4aa716c 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -21,6 +21,7 @@  #include "../../transport/super_send_packet_handler.hpp"  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include "fw_common.h"  #include <uhd/utils/log.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/utils/tasks.hpp> @@ -31,6 +32,7 @@  #include <boost/thread/thread.hpp>  #include <boost/format.hpp>  #include <boost/bind.hpp> +#include <boost/asio.hpp>  #include <boost/thread/mutex.hpp>  #include <boost/make_shared.hpp>  #include <iostream> @@ -361,6 +363,60 @@ bool usrp2_impl::recv_async_msg(  }  /*********************************************************************** + * Stream destination programmer + **********************************************************************/ +void usrp2_impl::program_stream_dest( +    zero_copy_if::sptr &xport, const uhd::stream_args_t &args +){ +    //perform an initial flush of transport +    while (xport->get_recv_buff(0.0)){} + +    //program the stream command +    usrp2_stream_ctrl_t stream_ctrl = usrp2_stream_ctrl_t(); +    stream_ctrl.sequence = uhd::htonx(boost::uint32_t(0 /* don't care seq num */)); +    stream_ctrl.vrt_hdr = uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)); + +    //user has provided an alternative address and port for destination +    if (args.args.has_key("addr") and args.args.has_key("port")){ +        UHD_MSG(status) << boost::format( +            "Programming streaming destination for custom address.\n" +            "IPv4 Address: %s, UDP Port: %s\n" +        ) % args.args["addr"] % args.args["port"] << std::endl; + +        asio::io_service io_service; +        asio::ip::udp::resolver resolver(io_service); +        asio::ip::udp::resolver::query query(asio::ip::udp::v4(), args.args["addr"], args.args["port"]); +        asio::ip::udp::endpoint endpoint = *resolver.resolve(query); +        stream_ctrl.ip_addr = uhd::htonx(boost::uint32_t(endpoint.address().to_v4().to_ulong())); +        stream_ctrl.udp_port = uhd::htonx(boost::uint32_t(endpoint.port())); + +        for (size_t i = 0; i < 3; i++){ +            UHD_MSG(status) << "ARP attempt " << i << std::endl; +            managed_send_buffer::sptr send_buff = xport->get_send_buff(); +            std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl)); +            send_buff->commit(sizeof(stream_ctrl)); +            boost::this_thread::sleep(boost::posix_time::milliseconds(300)); +            managed_recv_buffer::sptr recv_buff = xport->get_recv_buff(0.0); +            if (recv_buff and recv_buff->size() >= sizeof(boost::uint32_t)){ +                const boost::uint32_t result = uhd::ntohx(recv_buff->cast<const boost::uint32_t *>()[0]); +                if (result == 0){ +                    UHD_MSG(status) << "Success! " << std::endl; +                    return; +                } +            } +        } +        throw uhd::runtime_error("Device failed to ARP when programming alternative streaming destination."); +    } + +    else{ +        //send the partial stream control without destination +        managed_send_buffer::sptr send_buff = xport->get_send_buff(); +        std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl)); +        send_buff->commit(sizeof(stream_ctrl)/2); +    } +} + +/***********************************************************************   * Receive streamer   **********************************************************************/  rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){ @@ -406,6 +462,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){                  const size_t dsp = chan + _mbc[mb].rx_chan_occ - num_chan_so_far;                  _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this                  _mbc[mb].rx_dsps[dsp]->setup(args); +                this->program_stream_dest(_mbc[mb].rx_dsp_xports[dsp], args);                  my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(                      &zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1                  ), true /*flush*/); diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp new file mode 100644 index 000000000..3b8d215f5 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp @@ -0,0 +1,244 @@ +// +// Copyright 2012 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_regs.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/utils/safe_call.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include "usrp2_fifo_ctrl.hpp" +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/asio.hpp> //htonl +#include <boost/format.hpp> + +using namespace uhd; +using namespace uhd::transport; + +static const size_t POKE32_CMD = (1 << 8); +static const size_t PEEK32_CMD = 0; +static const double ACK_TIMEOUT = 0.5; +static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command +static const boost::uint32_t MAX_SEQS_OUT = 16; + +#define SPI_DIV SR_SPI_CORE + 0 +#define SPI_CTRL SR_SPI_CORE + 1 +#define SPI_DATA SR_SPI_CORE + 2 +#define SPI_READBACK 0 +// spi clock rate = master_clock/(div+1)/2 (10MHz in this case) +#define SPI_DIVIDER 4 + +class usrp2_fifo_ctrl_impl : public usrp2_fifo_ctrl{ +public: + +    usrp2_fifo_ctrl_impl(zero_copy_if::sptr xport): +        _xport(xport), +        _seq_out(0), +        _seq_ack(0), +        _timeout(ACK_TIMEOUT) +    { +        while (_xport->get_recv_buff(0.0)){} //flush +        this->set_time(uhd::time_spec_t(0.0)); +        this->set_tick_rate(1.0); //something possible but bogus +        this->init_spi(); +    } + +    ~usrp2_fifo_ctrl_impl(void){ +        _timeout = ACK_TIMEOUT; //reset timeout to something small +        UHD_SAFE_CALL( +            this->peek32(0); //dummy peek with the purpose of ack'ing all packets +        ) +    } + +    /******************************************************************* +     * Peek and poke 32 bit implementation +     ******************************************************************/ +    void poke32(wb_addr_type addr, boost::uint32_t data){ +        boost::mutex::scoped_lock lock(_mutex); + +        this->send_pkt((addr - SETTING_REGS_BASE)/4, data, POKE32_CMD); + +        this->wait_for_ack(_seq_out-MAX_SEQS_OUT); +    } + +    boost::uint32_t peek32(wb_addr_type addr){ +        boost::mutex::scoped_lock lock(_mutex); + +        this->send_pkt((addr - READBACK_BASE)/4, 0, PEEK32_CMD); + +        return this->wait_for_ack(_seq_out); +    } + +    /******************************************************************* +     * Peek and poke 16 bit not implemented +     ******************************************************************/ +    void poke16(wb_addr_type, boost::uint16_t){ +        throw uhd::not_implemented_error("poke16 not implemented in fifo ctrl module"); +    } + +    boost::uint16_t peek16(wb_addr_type){ +        throw uhd::not_implemented_error("peek16 not implemented in fifo ctrl module"); +    } + +    /******************************************************************* +     * FIFO controlled SPI implementation +     ******************************************************************/ +    void init_spi(void){ +        boost::mutex::scoped_lock lock(_mutex); + +        this->send_pkt(SPI_DIV, SPI_DIVIDER, POKE32_CMD); +        this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + +        _ctrl_word_cache = 0; // force update first time around +    } + +    boost::uint32_t transact_spi( +        int which_slave, +        const spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits, +        bool readback +    ){ +        boost::mutex::scoped_lock lock(_mutex); + +        //load control word +        boost::uint32_t ctrl_word = 0; +        ctrl_word |= ((which_slave & 0xffffff) << 0); +        ctrl_word |= ((num_bits & 0x3ff) << 24); +        if (config.mosi_edge == spi_config_t::EDGE_FALL) ctrl_word |= (1 << 31); +        if (config.miso_edge == spi_config_t::EDGE_RISE) ctrl_word |= (1 << 30); + +        //load data word (must be in upper bits) +        const boost::uint32_t data_out = data << (32 - num_bits); + +        //conditionally send control word +        if (_ctrl_word_cache != ctrl_word){ +            this->send_pkt(SPI_CTRL, ctrl_word, POKE32_CMD); +            this->wait_for_ack(_seq_out-MAX_SEQS_OUT); +            _ctrl_word_cache = ctrl_word; +        } + +        //send data word +        this->send_pkt(SPI_DATA, data_out, POKE32_CMD); +        this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + +        //conditional readback +        if (readback){ +            this->send_pkt(SPI_READBACK, 0, PEEK32_CMD); +            return this->wait_for_ack(_seq_out); +        } + +        return 0; +    } + +    /******************************************************************* +     * Update methods for time +     ******************************************************************/ +    void set_time(const uhd::time_spec_t &time){ +        boost::mutex::scoped_lock lock(_mutex); +        _time = time; +        _use_time = _time != uhd::time_spec_t(0.0); +        if (_use_time) _timeout = MASSIVE_TIMEOUT; //permanently sets larger timeout +    } + +    void set_tick_rate(const double rate){ +        boost::mutex::scoped_lock lock(_mutex); +        _tick_rate = rate; +    } + +private: + +    /******************************************************************* +     * Primary control and interaction private methods +     ******************************************************************/ +    UHD_INLINE void send_pkt(wb_addr_type addr, boost::uint32_t data, int cmd){ +        managed_send_buffer::sptr buff = _xport->get_send_buff(0.0); +        if (not buff){ +            throw uhd::runtime_error("fifo ctrl timed out getting a send buffer"); +        } +        boost::uint32_t *trans = buff->cast<boost::uint32_t *>(); +        trans[0] = htonl(++_seq_out); +        boost::uint32_t *pkt = trans + 1; + +        //load packet info +        vrt::if_packet_info_t packet_info; +        packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_CONTEXT; +        packet_info.num_payload_words32 = 2; +        packet_info.num_payload_bytes = packet_info.num_payload_words32*sizeof(boost::uint32_t); +        packet_info.packet_count = _seq_out; +        packet_info.tsf = _time.to_ticks(_tick_rate); +        packet_info.sob = false; +        packet_info.eob = false; +        packet_info.has_sid = false; +        packet_info.has_cid = false; +        packet_info.has_tsi = false; +        packet_info.has_tsf = _use_time; +        packet_info.has_tlr = false; + +        //load header +        vrt::if_hdr_pack_be(pkt, packet_info); + +        //load payload +        const boost::uint32_t ctrl_word = (addr & 0xff) | cmd | (_seq_out << 16); +        pkt[packet_info.num_header_words32+0] = htonl(ctrl_word); +        pkt[packet_info.num_header_words32+1] = htonl(data); + +        //send the buffer over the interface +        buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32+1)); +    } + +    UHD_INLINE bool wraparound_lt16(const boost::int16_t i0, const boost::int16_t i1){ +        if (((i0 ^ i1) & 0x8000) == 0) //same sign bits +            return boost::uint16_t(i0) < boost::uint16_t(i1); +        return boost::int16_t(i1 - i0) > 0; +    } + +    UHD_INLINE boost::uint32_t wait_for_ack(const boost::uint16_t seq_to_ack){ + +        while (wraparound_lt16(_seq_ack, seq_to_ack)){ +            managed_recv_buffer::sptr buff = _xport->get_recv_buff(_timeout); +            if (not buff){ +                throw uhd::runtime_error("fifo ctrl timed out looking for acks"); +            } +            const boost::uint32_t *pkt = buff->cast<const boost::uint32_t *>(); +            vrt::if_packet_info_t packet_info; +            packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); +            vrt::if_hdr_unpack_be(pkt, packet_info); +            _seq_ack = ntohl(pkt[packet_info.num_header_words32+0]) >> 16; +            if (_seq_ack == seq_to_ack){ +                return ntohl(pkt[packet_info.num_header_words32+1]); +            } +        } + +        return 0; +    } + +    zero_copy_if::sptr _xport; +    boost::mutex _mutex; +    boost::uint16_t _seq_out; +    boost::uint16_t _seq_ack; +    uhd::time_spec_t _time; +    bool _use_time; +    double _tick_rate; +    double _timeout; +    boost::uint32_t _ctrl_word_cache; +}; + + +usrp2_fifo_ctrl::sptr usrp2_fifo_ctrl::make(zero_copy_if::sptr xport){ +    return sptr(new usrp2_fifo_ctrl_impl(xport)); +} diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp new file mode 100644 index 000000000..b48d05aa2 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp @@ -0,0 +1,47 @@ +// +// Copyright 2012 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_FIFO_CTRL_HPP +#define INCLUDED_USRP2_FIFO_CTRL_HPP + +#include <uhd/types/time_spec.hpp> +#include <uhd/types/serial.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include "wb_iface.hpp" +#include <string> + +/*! + * The usrp2 FIFO control class: + * Provide high-speed peek/poke interface. + */ +class usrp2_fifo_ctrl : public wb_iface, public uhd::spi_iface{ +public: +    typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr; + +    //! Make a new FIFO control object +    static sptr make(uhd::transport::zero_copy_if::sptr xport); + +    //! Set the command time that will activate +    virtual void set_time(const uhd::time_spec_t &time) = 0; + +    //! Set the tick rate (converting time into ticks) +    virtual void set_tick_rate(const double rate) = 0; +}; + +#endif /* INCLUDED_USRP2_FIFO_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 123910166..a05710891 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 Ettus Research LLC  //  // This program is free software: you can redistribute it and/or modify  // it under the terms of the GNU General Public License as published by @@ -16,11 +16,13 @@  //  #include "usrp2_regs.hpp" +#include "usrp2_impl.hpp"  #include "fw_common.h"  #include "usrp2_iface.hpp"  #include <uhd/exception.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/utils/tasks.hpp> +#include <uhd/utils/images.hpp>  #include <uhd/utils/safe_call.hpp>  #include <uhd/types/dict.hpp>  #include <boost/thread.hpp> @@ -31,12 +33,14 @@  #include <boost/bind.hpp>  #include <boost/tokenizer.hpp>  #include <boost/functional/hash.hpp> +#include <boost/filesystem.hpp>  #include <algorithm>  #include <iostream>  using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::transport; +namespace fs = boost::filesystem;  static const double CTRL_RECV_TIMEOUT = 1.0;  static const size_t CTRL_RECV_RETRIES = 3; @@ -105,7 +109,7 @@ public:              throw uhd::runtime_error("firmware not responding");          _protocol_compat = ntohl(ctrl_data.proto_ver); -        mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_N100); +        mb_eeprom = mboard_eeprom_t(*this, USRP2_EEPROM_MAP_KEY);      }      ~usrp2_iface_impl(void){UHD_SAFE_CALL( @@ -311,8 +315,10 @@ public:                      "\nPlease update the firmware and FPGA images for your device.\n"                      "See the application notes for USRP2/N-Series for instructions.\n"                      "Expected protocol compatibility number %s, but got %d:\n" -                    "The firmware build is not compatible with the host code build." -                ) % ((lo == hi)? (boost::format("%d") % hi) : (boost::format("[%d to %d]") % lo % hi)) % compat)); +                    "The firmware build is not compatible with the host code build.\n" +                    "%s\n" +                ) % ((lo == hi)? (boost::format("%d") % hi) : (boost::format("[%d to %d]") % lo % hi)) +                  % compat % this->images_warn_help_message()));              }              if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){                  return *ctrl_data_in; @@ -340,13 +346,13 @@ public:      const std::string get_cname(void){          switch(this->get_rev()){ -        case USRP2_REV3: return "USRP2-REV3"; -        case USRP2_REV4: return "USRP2-REV4"; -        case USRP_N200: return "USRP-N200"; -        case USRP_N210: return "USRP-N210"; -        case USRP_N200_R4: return "USRP-N200-REV4"; -        case USRP_N210_R4: return "USRP-N210-REV4"; -        case USRP_NXXX: return "USRP-N???"; +        case USRP2_REV3: return "USRP2 r3"; +        case USRP2_REV4: return "USRP2 r4"; +        case USRP_N200: return "N200"; +        case USRP_N210: return "N210"; +        case USRP_N200_R4: return "N200r4"; +        case USRP_N210_R4: return "N210r4"; +        case USRP_NXXX: return "N???";          }          UHD_THROW_INVALID_CODE_PATH();      } @@ -356,6 +362,55 @@ public:          return str(boost::format("%u.%u") % _protocol_compat % minor);      } +    std::string images_warn_help_message(void){ +        //determine the images names +        std::string fw_image, fpga_image; +        switch(this->get_rev()){ +        case USRP2_REV3:   fpga_image = "usrp2_fpga.bin";        fw_image = "usrp2_fw.bin";     break; +        case USRP2_REV4:   fpga_image = "usrp2_fpga.bin";        fw_image = "usrp2_fw.bin";     break; +        case USRP_N200:    fpga_image = "usrp_n200_r2_fpga.bin"; fw_image = "usrp_n200_fw.bin"; break; +        case USRP_N210:    fpga_image = "usrp_n210_r2_fpga.bin"; fw_image = "usrp_n210_fw.bin"; break; +        case USRP_N200_R4: fpga_image = "usrp_n200_r4_fpga.bin"; fw_image = "usrp_n200_fw.bin"; break; +        case USRP_N210_R4: fpga_image = "usrp_n210_r4_fpga.bin"; fw_image = "usrp_n210_fw.bin"; break; +        default: break; +        } +        if (fw_image.empty() or fpga_image.empty()) return ""; + +        //look up the real FS path to the images +        std::string fw_image_path, fpga_image_path; +        try{ +            fw_image_path = uhd::find_image_path(fw_image); +            fpga_image_path = uhd::find_image_path(fpga_image); +        } +        catch(const std::exception &){ +            return str(boost::format("Could not find %s and %s in your images path!") % fw_image % fpga_image); +        } + +        //does your platform use sudo? +        std::string sudo; +        #if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_MACOS) +            sudo = "sudo"; +        #endif + +        //escape char for multi-line cmd + newline + indent? +        #ifdef UHD_PLATFORM_WIN32 +            const std::string ml = "^\n    "; +        #else +            const std::string ml = "\\\n    "; +        #endif + +        //create the burner command +        if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){ +            const std::string card_burner = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp2_card_burner_gui.py").string(); +            return str(boost::format("Please run:\n%s \"%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path); +        } +        else{ +            const std::string addr = _ctrl_transport->get_recv_addr(); +            const std::string net_burner = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp_n2xx_net_burner_gui.py").string(); +            return str(boost::format("Please run:\n\"%s\" %s--fpga=\"%s\" %s--fw=\"%s\" %s--addr=\"%s\"") % net_burner % ml % fpga_image_path % ml % fw_image_path % ml % addr); +        } +    } +  private:      //this lovely lady makes it all possible      udp_simple::sptr _ctrl_transport; diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 9aa1a16aa..95d899b7f 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -69,6 +69,9 @@ public:      //! A version string for firmware      virtual const std::string get_fw_version_string(void) = 0; +    //! Construct a helpful warning message for images +    virtual std::string images_warn_help_message(void) = 0; +      //motherboard eeprom map structure      uhd::usrp::mboard_eeprom_t mb_eeprom;  }; diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index e6e8ca675..604f2f832 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -368,8 +368,9 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){                  "\nPlease update the firmware and FPGA images for your device.\n"                  "See the application notes for USRP2/N-Series for instructions.\n"                  "Expected FPGA compatibility number %d, but got %d:\n" -                "The FPGA build is not compatible with the host code build." -            ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major)); +                "The FPGA build is not compatible with the host code build.\n" +                "%s\n" +            ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major % _mbc[mb].iface->images_warn_help_message()));          }          _tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor)); @@ -391,8 +392,28 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          _mbc[mb].tx_dsp_xport = make_xport(              addr, BOOST_STRINGIZE(USRP2_UDP_TX_DSP0_PORT), device_args_i, "send"          ); +        UHD_LOG << "Making transport for Control..." << std::endl; +        _mbc[mb].fifo_ctrl_xport = make_xport( +            addr, BOOST_STRINGIZE(USRP2_UDP_FIFO_CRTL_PORT), device_addr_t(), "" +        );          //set the filter on the router to take dsp data from this port -        _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, USRP2_UDP_TX_DSP0_PORT); +        _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, (USRP2_UDP_FIFO_CRTL_PORT << 16) | USRP2_UDP_TX_DSP0_PORT); + +        //create the fifo control interface for high speed register access +        _mbc[mb].fifo_ctrl = usrp2_fifo_ctrl::make(_mbc[mb].fifo_ctrl_xport); +        switch(_mbc[mb].iface->get_rev()){ +        case usrp2_iface::USRP_N200: +        case usrp2_iface::USRP_N210: +        case usrp2_iface::USRP_N200_R4: +        case usrp2_iface::USRP_N210_R4: +            _mbc[mb].wbiface = _mbc[mb].fifo_ctrl; +            _mbc[mb].spiface = _mbc[mb].fifo_ctrl; +            break; +        default: +            _mbc[mb].wbiface = _mbc[mb].iface; +            _mbc[mb].spiface = _mbc[mb].iface; +            break; +        }          ////////////////////////////////////////////////////////////////          // setup the mboard eeprom @@ -404,7 +425,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          ////////////////////////////////////////////////////////////////          // create clock control objects          //////////////////////////////////////////////////////////////// -        _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface); +        _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface, _mbc[mb].spiface);          _tree->create<double>(mb_path / "tick_rate")              .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock))              .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1)); @@ -416,7 +437,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          const fs_path tx_codec_path = mb_path / "tx_codecs/A";          _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists          _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists -        _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface); +        _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface, _mbc[mb].spiface);          switch(_mbc[mb].iface->get_rev()){          case usrp2_iface::USRP_N200:          case usrp2_iface::USRP_N210: @@ -469,10 +490,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create frontend control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].rx_fe = rx_frontend_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT) +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_FRONT)          );          _mbc[mb].tx_fe = tx_frontend_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT) +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TX_FRONT)          );          _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") @@ -503,10 +524,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create rx dsp control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true          ));          _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true          ));          for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){              _mbc[mb].rx_dsps[dspno]->set_link_rate(USRP2_LINK_RATE_BPS); @@ -531,7 +552,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create tx dsp control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].tx_dsp = tx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID          );          _mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS);          _tree->access<double>(mb_path / "tick_rate") @@ -565,7 +586,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS;          time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_RB_PPS;          _mbc[mb].time64 = time64_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles +            _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles          );          _tree->access<double>(mb_path / "tick_rate")              .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1)); @@ -585,11 +606,23 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){              .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));          static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");          _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); +        //plug timed commands into tree here +        switch(_mbc[mb].iface->get_rev()){ +        case usrp2_iface::USRP_N200: +        case usrp2_iface::USRP_N210: +        case usrp2_iface::USRP_N200_R4: +        case usrp2_iface::USRP_N210_R4: +            _tree->create<time_spec_t>(mb_path / "time/cmd") +                .subscribe(boost::bind(&usrp2_fifo_ctrl::set_time, _mbc[mb].fifo_ctrl, _1)); +        default: break; //otherwise, do not register +        } +        _tree->access<double>(mb_path / "tick_rate") +            .subscribe(boost::bind(&usrp2_fifo_ctrl::set_tick_rate, _mbc[mb].fifo_ctrl, _1));          ////////////////////////////////////////////////////////////////////          // create user-defined control objects          //////////////////////////////////////////////////////////////////// -        _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS)); +        _mbc[mb].user = user_settings_core_200::make(_mbc[mb].wbiface, U2_REG_SR_ADDR(SR_USER_REGS));          _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")              .subscribe(boost::bind(&user_settings_core_200::set_reg, _mbc[mb].user, _1)); @@ -615,7 +648,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){              .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1));          //create a new dboard interface and manager -        _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock); +        _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].wbiface, _mbc[mb].iface/*i2c*/, _mbc[mb].spiface, _mbc[mb].clock);          _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface);          _mbc[mb].dboard_manager = dboard_manager::make(              rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, @@ -675,7 +708,7 @@ usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(  )}  void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){ -    mb_eeprom.commit(*(_mbc[mb].iface), mboard_eeprom_t::MAP_N100); +    mb_eeprom.commit(*(_mbc[mb].iface), USRP2_EEPROM_MAP_KEY);  }  void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ @@ -685,12 +718,12 @@ void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, c  }  sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){ -    const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0; +    const bool lock = (_mbc[mb].wbiface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0;      return sensor_value_t("MIMO", lock, "locked", "unlocked");  }  sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){ -    const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0; +    const bool lock = (_mbc[mb].wbiface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0;      return sensor_value_t("Ref", lock, "locked", "unlocked");  } @@ -729,13 +762,14 @@ meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){  }  void usrp2_impl::update_clock_source(const std::string &mb, const std::string &source){ +    //NOTICE: U2_REG_MISC_CTRL_CLOCK is on the wb clock, and cannot be set from fifo_ctrl      //clock source ref 10mhz      switch(_mbc[mb].iface->get_rev()){      case usrp2_iface::USRP_N200:      case usrp2_iface::USRP_N210:      case usrp2_iface::USRP_N200_R4:      case usrp2_iface::USRP_N210_R4: -        if (source == "internal")       _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); +        if      (source == "internal")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12);          else if (source == "external")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);          else if (source == "mimo")      _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);          else throw uhd::value_error("unhandled clock configuration reference source: " + source); @@ -744,7 +778,7 @@ void usrp2_impl::update_clock_source(const std::string &mb, const std::string &s      case usrp2_iface::USRP2_REV3:      case usrp2_iface::USRP2_REV4: -        if (source == "internal")       _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); +        if      (source == "internal")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);          else if (source == "external")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);          else if (source == "mimo")      _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);          else throw uhd::value_error("unhandled clock configuration reference source: " + source); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e5065c02d..a6c0d87cf 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -18,7 +18,9 @@  #ifndef INCLUDED_USRP2_IMPL_HPP  #define INCLUDED_USRP2_IMPL_HPP +#include "gpio_core_200.hpp"  #include "usrp2_iface.hpp" +#include "usrp2_fifo_ctrl.hpp"  #include "clock_ctrl.hpp"  #include "codec_ctrl.hpp"  #include "rx_frontend_core_200.hpp" @@ -51,15 +53,13 @@ static const size_t mimo_clock_sync_delay_cycles = 138;  static const size_t USRP2_SRAM_BYTES = size_t(1 << 20);  static const boost::uint32_t USRP2_TX_ASYNC_SID = 2;  static const boost::uint32_t USRP2_RX_SID_BASE = 3; +static const std::string USRP2_EEPROM_MAP_KEY = "N100"; -/*! - * Make a usrp2 dboard interface. - * \param iface the usrp2 interface object - * \param clk_ctrl the clock control object - * \return a sptr to a new dboard interface - */ +//! Make a usrp2 dboard interface.  uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clk_ctrl  ); @@ -82,6 +82,9 @@ private:      uhd::property_tree::sptr _tree;      struct mb_container_type{          usrp2_iface::sptr iface; +        usrp2_fifo_ctrl::sptr fifo_ctrl; +        uhd::spi_iface::sptr spiface; +        wb_iface::sptr wbiface;          usrp2_clock_ctrl::sptr clock;          usrp2_codec_ctrl::sptr codec;          uhd::gps_ctrl::sptr gps; @@ -95,6 +98,7 @@ private:          user_settings_core_200::sptr user;          std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports;          uhd::transport::zero_copy_if::sptr tx_dsp_xport; +        uhd::transport::zero_copy_if::sptr fifo_ctrl_xport;          uhd::usrp::dboard_manager::sptr dboard_manager;          uhd::usrp::dboard_iface::sptr dboard_iface;          size_t rx_chan_occ, tx_chan_occ; @@ -129,6 +133,7 @@ private:      double set_tx_dsp_freq(const std::string &, const double);      uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);      void update_clock_source(const std::string &, const std::string &); +    void program_stream_dest(uhd::transport::zero_copy_if::sptr &, const uhd::stream_args_t &);  };  #endif /* INCLUDED_USRP2_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index e14798ecb..7fe83e709 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -36,10 +36,10 @@  // Setting register offsets  ////////////////////////////////////////////////////////////////////////  #define SR_MISC       0   // 7 regs -#define SR_SIMTIMER   8   // 2 +#define SR_USER_REGS  8   // 2  #define SR_TIME64    10   // 6  #define SR_BUF_POOL  16   // 4 -#define SR_USER_REGS 20   // 2 +#define SR_SPI_CORE  20   // 3  #define SR_RX_FRONT  24   // 5  #define SR_RX_CTRL0  32   // 9  #define SR_RX_DSP0   48   // 7 | 
