aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-06-29 14:00:22 -0700
committerJosh Blum <josh@joshknows.com>2011-06-29 14:00:22 -0700
commit11539ef6f690b4ebd69485be9a61f5422d8cdc99 (patch)
tree529cf29a314ac5b8b3dfaab94f98caca972cc462 /host
parentbc8aaf3952f1c192030d1c9a0b6ddcbe14d9c062 (diff)
downloaduhd-11539ef6f690b4ebd69485be9a61f5422d8cdc99.tar.gz
uhd-11539ef6f690b4ebd69485be9a61f5422d8cdc99.tar.bz2
uhd-11539ef6f690b4ebd69485be9a61f5422d8cdc99.zip
usrp2: moved impl back into usrp subdir
Diffstat (limited to 'host')
-rw-r--r--host/lib/CMakeLists.txt1
-rw-r--r--host/lib/usrp/CMakeLists.txt2
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt35
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp181
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp183
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp256
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp187
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp522
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp10
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp11
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp431
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp189
-rw-r--r--host/lib/usrp2/CMakeLists.txt28
-rw-r--r--host/lib/usrp2/clock_ctrl.cpp377
-rw-r--r--host/lib/usrp2/clock_ctrl.hpp109
-rw-r--r--host/lib/usrp2/codec_ctrl.cpp216
-rw-r--r--host/lib/usrp2/codec_ctrl.hpp68
-rw-r--r--host/lib/usrp2/dboard_iface.cpp350
-rw-r--r--host/lib/usrp2/fw_common.h154
-rw-r--r--host/lib/usrp2/io_impl.cpp422
-rw-r--r--host/lib/usrp2/usrp2_clk_regs.hpp87
-rw-r--r--host/lib/usrp2/usrp2_iface.cpp412
-rw-r--r--host/lib/usrp2/usrp2_iface.hpp80
-rw-r--r--host/lib/usrp2/usrp2_impl.cpp673
-rw-r--r--host/lib/usrp2/usrp2_impl.hpp134
-rw-r--r--host/lib/usrp2/usrp2_regs.hpp221
26 files changed, 561 insertions, 4778 deletions
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index a8f490f0a..60ddbce5b 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -72,7 +72,6 @@ INCLUDE_SUBDIRECTORY(types)
INCLUDE_SUBDIRECTORY(convert)
INCLUDE_SUBDIRECTORY(transport)
INCLUDE_SUBDIRECTORY(usrp)
-INCLUDE_SUBDIRECTORY(usrp2)
INCLUDE_SUBDIRECTORY(utils)
########################################################################
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 21e44509c..2a9939d0b 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -34,6 +34,6 @@ INCLUDE_SUBDIRECTORY(cores)
INCLUDE_SUBDIRECTORY(dboard)
INCLUDE_SUBDIRECTORY(fx2)
#INCLUDE_SUBDIRECTORY(usrp1)
-#INCLUDE_SUBDIRECTORY(usrp2)
+INCLUDE_SUBDIRECTORY(usrp2)
#INCLUDE_SUBDIRECTORY(b100)
#INCLUDE_SUBDIRECTORY(e100)
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index c3f138c24..d16976060 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011 Ettus Research LLC
+# Copyright 2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,28 +18,11 @@
########################################################################
# This file included, use CMake directory variables
########################################################################
-
-########################################################################
-# Conditionally configure the USRP2 support
-########################################################################
-LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF)
-
-IF(ENABLE_USRP2)
- LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_regs.hpp
- )
-ENDIF(ENABLE_USRP2)
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
+)
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
deleted file mode 100644
index 26da42759..000000000
--- a/host/lib/usrp/usrp2/codec_impl.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 <uhd/utils/assert_has.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <uhd/types/dict.hpp>
-#include <uhd/types/ranges.hpp>
-#include <boost/bind.hpp>
-#include <boost/assign/list_of.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace boost::assign;
-
-//this only applies to N2XX
-static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of
- ("digital", gain_range_t(0, 6.0, 0.5))
- ("digital-fine", gain_range_t(0, 0.5, 0.05));
-
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp2_mboard_impl::codec_init(void){
- //make proxies
- _rx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2)
- );
- _tx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2)
- );
-
- //initialize gain names. keeps get_rx_gain() from getting a gain
- //that hasn't been set yet.
- BOOST_FOREACH(std::string key, codec_rx_gain_ranges.keys()) {
- _codec_rx_gains[key] = codec_rx_gain_ranges[key].start();
- }
-}
-
-/***********************************************************************
- * RX Codec Properties
- **********************************************************************/
-void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- switch(_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:
- val = _iface->get_cname() + " adc - ads62p44";
- break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- val = _iface->get_cname() + " adc - ltc2284";
- break;
-
- case usrp2_iface::USRP_NXXX:
- val = _iface->get_cname() + " adc - ??????";
- break;
- }
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- val = prop_names_t(codec_rx_gain_ranges.keys());
- return;
-
- default: val = prop_names_t();
- }
- return;
-
- case CODEC_PROP_GAIN_I:
- case CODEC_PROP_GAIN_Q:
- assert_has(_codec_rx_gains.keys(), key.name, "codec rx gain name");
- val = _codec_rx_gains[key.name];
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- assert_has(codec_rx_gain_ranges.keys(), key.name, "codec rx gain range name");
- val = codec_rx_gain_ranges[key.name];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<codec_prop_t>()) {
- case CODEC_PROP_GAIN_I:
- case CODEC_PROP_GAIN_Q:
- this->rx_codec_set_gain(val.as<double>(), key.name);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * Helper function to set RX codec gain
- ***********************************************************************/
-
-void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){
- assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name");
-
- _codec_rx_gains[name] = gain;
-/*
- if(name == "analog") {
- _codec_ctrl->set_rx_analog_gain(gain > 0); //just turn it on or off
- return;
- }
-*/
- if(name == "digital") {
- _codec_ctrl->set_rx_digital_gain(gain);
- return;
- }
- if(name == "digital-fine") {
- _codec_ctrl->set_rx_digital_fine_gain(gain);
- return;
- }
- UHD_THROW_PROP_SET_ERROR();
-}
-
-
-/***********************************************************************
- * TX Codec Properties
- **********************************************************************/
-void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = _iface->get_cname() + " dac - ad9777";
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(); //no gain elements to be controlled
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){
- UHD_THROW_PROP_SET_ERROR();
-}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
deleted file mode 100644
index 8c6379d66..000000000
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "fw_common.h"
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/exception.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;
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp2_mboard_impl::dboard_init(void){
- //read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB);
- _tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB);
- _gdb_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
-
- //create a new dboard interface and manager
- _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
- _dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id,
- ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
- _dboard_iface
- );
-
- //load dboards
- _rx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2)
- );
- _tx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX DBoard Properties
- **********************************************************************/
-void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = _iface->get_cname() + " dboard (rx unit)";
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_rx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_rx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _rx_db_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _rx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _rx_db_eeprom.id,
- _dboard_manager->get_rx_subdev(key.name),
- _rx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_RX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
-
- case DBOARD_PROP_DBOARD_EEPROM:
- _rx_db_eeprom = val.as<dboard_eeprom_t>();
- _rx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_RX_DB);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DBoard Properties
- **********************************************************************/
-void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = _iface->get_cname() + " dboard (tx unit)";
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_tx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_tx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _tx_db_eeprom;
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- val = _gdb_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _tx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _tx_db_eeprom.id,
- _dboard_manager->get_tx_subdev(key.name),
- _tx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_TX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
-
- case DBOARD_PROP_DBOARD_EEPROM:
- _tx_db_eeprom = val.as<dboard_eeprom_t>();
- _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB);
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- _gdb_eeprom = val.as<dboard_eeprom_t>();
- _gdb_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
deleted file mode 100644
index d9cde3f13..000000000
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <boost/math/special_functions/sign.hpp>
-#include <algorithm>
-#include <cmath>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * DSP impl and methods
- **********************************************************************/
-struct usrp2_mboard_impl::dsp_impl{
- uhd::dict<size_t, size_t> ddc_decim;
- uhd::dict<size_t, double> ddc_freq;
- uhd::dict<size_t, size_t> duc_interp;
- uhd::dict<size_t, double> duc_freq;
- std::vector<size_t> decim_and_interp_rates;
- uhd::dict<size_t, bool> continuous_streaming;
-};
-
-void usrp2_mboard_impl::dsp_init(void){
- //create new dsp impl
- _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ());
-
- //load the allowed decim/interp rates
- //range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
- for (size_t i = 4; i <= 128; i+=1){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
- for (size_t i = 130; i <= 256; i+=2){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
- for (size_t i = 260; i <= 512; i+=4){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
-
- //bind and initialize the rx dsps
- for (size_t i = 0; i < NUM_RX_DSPS; i++){
- _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2, i),
- boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2, i)
- );
-
- //initial config and update
- ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i);
- ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i);
-
- //setup the rx control registers
- _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //reset
- _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PP(i), _device.get_max_recv_samps_per_packet());
- _iface->poke32(U2_REG_RX_CTRL_NCHANNELS(i), 1);
- _iface->poke32(U2_REG_RX_CTRL_VRT_HDR(i), 0
- | (0x1 << 28) //if data with stream id
- | (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
- | (0x1 << 20) //fractional time sample count
- );
- _iface->poke32(U2_REG_RX_CTRL_VRT_SID(i), usrp2_impl::RECV_SID);
- _iface->poke32(U2_REG_RX_CTRL_VRT_TLR(i), 0);
- _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
- }
-
- //bind and initialize the tx dsps
- for (size_t i = 0; i < NUM_TX_DSPS; i++){
- _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2, i),
- boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2, i)
- );
-
- //initial config and update
- duc_set(DSP_PROP_FREQ_SHIFT, double(0), i);
- duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i);
-
- //init the tx control registers
- _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
- _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
- _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, usrp2_impl::ASYNC_SID);
- _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
- }
-}
-
-template <typename rate_type>
-static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){
- unsigned closest_match = rates.front();
- BOOST_FOREACH(rate_type possible_rate, rates){
- if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match))
- closest_match = possible_rate;
- }
- return closest_match;
-}
-
-void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t which_dsp){
- _dsp_impl->continuous_streaming[which_dsp] = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD(which_dsp), dsp_type1::calc_stream_cmd_word(stream_cmd));
- _iface->poke32(U2_REG_RX_CTRL_TIME_SECS(which_dsp), boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS(which_dsp), stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
-}
-
-/***********************************************************************
- * DDC Properties
- **********************************************************************/
-void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp);
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _dsp_impl->ddc_freq[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = get_master_clock_freq()/_dsp_impl->ddc_decim[which_dsp];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_STREAM_CMD:
- issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp);
- return;
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(U2_REG_DSP_RX_FREQ(which_dsp),
- dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq())
- );
- _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- double extact_rate = get_master_clock_freq()/val.as<double>();
- _dsp_impl->ddc_decim[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates);
-
- //set the decimation
- _iface->poke32(U2_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp]));
- }
- _device.update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * DUC Properties
- **********************************************************************/
-void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp);
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _dsp_impl->duc_freq[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = get_master_clock_freq()/_dsp_impl->duc_interp[which_dsp];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_FREQ_SHIFT:{
- const double codec_rate = get_master_clock_freq();
- double new_freq = val.as<double>();
-
- //calculate the DAC shift (multiples of rate)
- const int sign = boost::math::sign(new_freq);
- const int zone = std::min(boost::math::iround(new_freq/codec_rate), 2);
- const double dac_shift = sign*zone*codec_rate;
- new_freq -= dac_shift; //update FPGA DSP target freq
-
- //set the DAC shift (modulation mode)
- if (zone == 0) _codec_ctrl->set_tx_mod_mode(0); //no shift
- else _codec_ctrl->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
-
- _iface->poke32(U2_REG_DSP_TX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, codec_rate)
- );
- _dsp_impl->duc_freq[which_dsp] = new_freq + dac_shift; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- double extact_rate = get_master_clock_freq()/val.as<double>();
- _dsp_impl->duc_interp[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates);
-
- //set the interpolation
- _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp]));
-
- //set the scaling
- _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp]));
- }
- _device.update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index df452942c..64c099ff6 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -22,8 +22,6 @@
#include <uhd/utils/log.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dsp_props.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/transport/bounded_buffer.hpp>
@@ -134,15 +132,10 @@ private:
**********************************************************************/
struct usrp2_impl::io_impl{
- io_impl(std::vector<zero_copy_if::sptr> &dsp_xports):
- dsp_xports(dsp_xports), //the assumption is that all data transports should be identical
+ io_impl(void):
async_msg_fifo(100/*messages deep*/)
{
- for (size_t i = 0; i < dsp_xports.size(); i++){
- fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
- usrp2_impl::sram_bytes/dsp_xports.front()->get_send_frame_size()
- )));
- }
+ /* NOP */
}
~io_impl(void){
@@ -151,14 +144,13 @@ struct usrp2_impl::io_impl{
}
managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){
- const size_t index = send_map[chan];
- flow_control_monitor &fc_mon = *fc_mons[index];
+ flow_control_monitor &fc_mon = *fc_mons[chan];
//wait on flow control w/ timeout
if (not fc_mon.check_fc_condition(timeout)) return managed_send_buffer::sptr();
//get a buffer from the transport w/ timeout
- managed_send_buffer::sptr buff = dsp_xports[index]->get_send_buff(timeout);
+ managed_send_buffer::sptr buff = tx_xports[chan]->get_send_buff(timeout);
//write the flow control word into the buffer
if (buff.get()) buff->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_mon.get_curr_seq_out());
@@ -166,15 +158,8 @@ struct usrp2_impl::io_impl{
return buff;
}
- std::vector<zero_copy_if::sptr> &dsp_xports;
-
- //mappings from channel index to dsp xport
- std::vector<size_t> send_map, recv_map;
-
- //previous state for each buffer
- std::vector<vrt::if_packet_info_t> prev_infos;
-
- //flow control monitors
+ //tx dsp: xports and flow control monitors
+ std::vector<zero_copy_if::sptr> tx_xports;
std::vector<flow_control_monitor::sptr> fc_mons;
//state management for the vrt packet handler code
@@ -182,9 +167,10 @@ struct usrp2_impl::io_impl{
sph::send_packet_handler send_handler;
//methods and variables for the pirate crew
- void recv_pirate_loop(boost::barrier &, usrp2_mboard_impl::sptr, zero_copy_if::sptr, size_t);
+ void recv_pirate_loop(boost::barrier &, zero_copy_if::sptr, size_t);
boost::thread_group recv_pirate_crew;
bounded_buffer<async_metadata_t> async_msg_fifo;
+ double tick_rate;
};
/***********************************************************************
@@ -195,7 +181,6 @@ struct usrp2_impl::io_impl{
**********************************************************************/
void usrp2_impl::io_impl::recv_pirate_loop(
boost::barrier &spawn_barrier,
- usrp2_mboard_impl::sptr mboard,
zero_copy_if::sptr err_xport,
size_t index
){
@@ -203,7 +188,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(
set_thread_priority_safe();
//store a reference to the flow control monitor (offset by max dsps)
- flow_control_monitor &fc_mon = *(this->fc_mons[index*usrp2_mboard_impl::MAX_NUM_DSPS]);
+ flow_control_monitor &fc_mon = *(this->fc_mons[index]);
while (not boost::this_thread::interruption_requested()){
managed_recv_buffer::sptr buff = err_xport->get_recv_buff();
@@ -217,14 +202,14 @@ void usrp2_impl::io_impl::recv_pirate_loop(
vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
//handle a tx async report message
- if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+ if (if_packet_info.sid == USRP2_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
//fill in the async metadata
async_metadata_t metadata;
metadata.channel = index;
metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
+ time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate
);
metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
@@ -254,80 +239,126 @@ void usrp2_impl::io_impl::recv_pirate_loop(
**********************************************************************/
void usrp2_impl::io_init(void){
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+
//create new io impl
- _io_impl = UHD_PIMPL_MAKE(io_impl, (dsp_xports));
+ _io_impl = UHD_PIMPL_MAKE(io_impl, ());
+
+ //init first so we dont have an access race
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ //init the tx xport and flow control monitor
+ _io_impl->tx_xports.push_back(_mbc[mb].dsp_xports.at(0));
+ _io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
+ USRP2_SRAM_BYTES/_mbc[mb].dsp_xports.at(0)->get_send_frame_size()
+ )));
+ }
//create a new pirate thread for each zc if (yarr!!)
- boost::barrier spawn_barrier(_mboards.size()+1);
- for (size_t i = 0; i < _mboards.size(); i++){
+ boost::barrier spawn_barrier(_mbc.size()+1);
+ size_t index = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
//spawn a new pirate to plunder the recv booty
_io_impl->recv_pirate_crew.create_thread(boost::bind(
&usrp2_impl::io_impl::recv_pirate_loop,
_io_impl.get(), boost::ref(spawn_barrier),
- _mboards.at(i), err_xports.at(i), i
+ _mbc[mb].err_xports.at(0), index++
));
}
spawn_barrier.wait();
- //update mapping here since it didnt b4 when io init not called first
- update_xport_channel_mapping();
+ //init some handler stuff
+ _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be);
+ _io_impl->recv_handler.set_converter(_rx_otw_type);
+ _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32);
+ _io_impl->send_handler.set_converter(_tx_otw_type);
+ _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
}
-void usrp2_impl::update_xport_channel_mapping(void){
- if (_io_impl.get() == NULL) return; //not inited yet
+void usrp2_impl::update_tick_rate(const double rate){
+ _io_impl->tick_rate = rate;
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_tick_rate(rate);
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_tick_rate(rate);
+}
- _io_impl->recv_map.clear();
- _io_impl->send_map.clear();
+void usrp2_impl::update_rx_samp_rate(const double rate){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_samp_rate(rate);
+}
- for (size_t i = 0; i < _mboards.size(); i++){
+void usrp2_impl::update_tx_samp_rate(const double rate){
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_samp_rate(rate);
+}
- subdev_spec_t rx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
- for (size_t j = 0; j < rx_subdev_spec.size(); j++){
- _io_impl->recv_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j);
- UHD_LOG << "recv_map.back() " << _io_impl->recv_map.back() << std::endl;
- }
+void usrp2_impl::update_rx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
- subdev_spec_t tx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
- for (size_t j = 0; j < tx_subdev_spec.size(); j++){
- _io_impl->send_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j);
- UHD_LOG << "send_map.back() " << _io_impl->send_map.back() << std::endl;
- }
+ //sanity checking
+ if (spec.size() == 0) throw uhd::value_error("rx subdev spec cant be empty");
+ if (spec.size() > _mbc[which_mb].rx_dsps.size()) throw uhd::value_error("rx subdev spec too long");
+ //setup mux for this spec
+ for (size_t i = 0; i < spec.size(); i++){
+ //ASSUME that we dont swap the rx fe mux...
+ const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get();
+ _mbc[which_mb].rx_dsps[i]->set_mux(conn);
}
- //set all of the relevant properties on the handler
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.resize(_io_impl->recv_map.size());
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be);
- _io_impl->recv_handler.set_tick_rate(_mboards.front()->get_master_clock_freq());
- //TODO temporarily use the first dsp rate until we support non-homo rates
- const std::string rx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>().at(0);
- const double rx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_RX_DSP, rx_dsp_name)][DSP_PROP_HOST_RATE].as<double>();
- _io_impl->recv_handler.set_samp_rate(rx_host_rate);
- for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){
- _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind(
- &uhd::transport::zero_copy_if::get_recv_buff,
- _io_impl->dsp_xports[_io_impl->recv_map[chan]], _1
- ));
+ //compute the new occupancy and resize
+ _mbc[which_mb].rx_chan_occ = spec.size();
+ size_t nchan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].rx_chan_occ;
+ _io_impl->recv_handler.resize(nchan);
+
+ //bind new callbacks for the handler
+ size_t chan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ for (size_t dsp = 0; dsp < _mbc[mb].rx_chan_occ; dsp++){
+ _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
+ _io_impl->recv_handler.set_xport_chan_get_buff(chan++, boost::bind(
+ &zero_copy_if::get_recv_buff, _mbc[mb].dsp_xports[dsp], _1
+ ));
+ }
}
- _io_impl->recv_handler.set_converter(_rx_otw_type);
+}
- //set all of the relevant properties on the handler
+void usrp2_impl::update_tx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){
boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.resize(_io_impl->send_map.size());
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32);
- _io_impl->send_handler.set_tick_rate(_mboards.front()->get_master_clock_freq());
- //TODO temporarily use the first dsp rate until we support non-homo rates
- const std::string tx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>().at(0);
- const double tx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_TX_DSP, tx_dsp_name)][DSP_PROP_HOST_RATE].as<double>();
- _io_impl->send_handler.set_samp_rate(tx_host_rate);
- for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){
- _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind(
- &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), chan, _1
- ));
+ property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
+
+ //sanity checking
+ if (spec.size() != 1) throw uhd::value_error("tx subdev spec has to be size 1");
+
+ //set the mux for this spec
+ const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
+ _mbc[which_mb].tx_fe->set_mux(conn);
+
+ //compute the new occupancy and resize
+ _mbc[which_mb].tx_chan_occ = spec.size();
+ size_t nchan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].tx_chan_occ;
+ _io_impl->send_handler.resize(nchan);
+
+ //bind new callbacks for the handler
+ size_t chan = 0, i = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ for (size_t dsp = 0; dsp < _mbc[mb].tx_chan_occ; dsp++){
+ _io_impl->send_handler.set_xport_chan_get_buff(chan++, boost::bind(
+ &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), i++, _1
+ ));
+ }
}
- _io_impl->send_handler.set_converter(_tx_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
}
/***********************************************************************
@@ -349,7 +380,7 @@ size_t usrp2_impl::get_max_send_samps_per_packet(void) const{
+ vrt_send_header_offset_words32*sizeof(boost::uint32_t)
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- const size_t bpp = dsp_xports.front()->get_send_frame_size() - hdr_size;
+ const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_send_frame_size() - hdr_size;
return bpp/_tx_otw_type.get_sample_size();
}
@@ -374,7 +405,7 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- const size_t bpp = dsp_xports.front()->get_recv_frame_size() - hdr_size;
+ const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_recv_frame_size() - hdr_size;
return bpp/_rx_otw_type.get_sample_size();
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
deleted file mode 100644
index 5583a4335..000000000
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "fw_common.h"
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/gps_ctrl.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <uhd/types/sensors.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/bind.hpp>
-
-static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
-static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
-static const size_t mimo_clock_sync_delay_cycles = 137;
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-/***********************************************************************
- * Helpers
- **********************************************************************/
-static void init_xport(zero_copy_if::sptr xport){
- //Send a small data packet so the usrp2 knows the udp source port.
- //This setup must happen before further initialization occurs
- //or the async update packets will cause ICMP destination unreachable.
- static const boost::uint32_t data[2] = {
- uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
- uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
- };
-
- transport::managed_send_buffer::sptr send_buff = xport->get_send_buff();
- std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
- send_buff->commit(sizeof(data));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_mboard_impl::usrp2_mboard_impl(
- const device_addr_t &device_addr,
- size_t index, usrp2_impl &device
-):
- _index(index), _device(device),
- _iface(usrp2_iface::make(udp_simple::make_connected(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
- )))
-{
-
- //check the fpga compatibility number
- const boost::uint32_t fpga_compat_num = _iface->peek32(U2_REG_COMPAT_NUM_RB);
- if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "\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_compat_num));
- }
-
- //lock the device/motherboard to this process
- _iface->lock_device(true);
-
- //construct transports for dsp and async errors
- UHD_LOG << "Making transport for DSP0..." << std::endl;
- device.dsp_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_addr
- ));
- init_xport(device.dsp_xports.back());
-
- UHD_LOG << "Making transport for DSP1..." << std::endl;
- device.dsp_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_addr
- ));
- init_xport(device.dsp_xports.back());
-
- UHD_LOG << "Making transport for ERR0..." << std::endl;
- device.err_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t()
- ));
- init_xport(device.err_xports.back());
-
- //contruct the interfaces to mboard perifs
- _clock_ctrl = usrp2_clock_ctrl::make(_iface);
- _codec_ctrl = usrp2_codec_ctrl::make(_iface);
- if (_iface->mb_eeprom["gpsdo"] == "internal"){
- _gps_ctrl = gps_ctrl::make(
- _iface->get_gps_write_fn(),
- _iface->get_gps_read_fn());
- }
-
- //init the dsp stuff (before setting update packets)
- dsp_init();
-
- //setting the cycles per update (disabled by default)
- const double ups_per_sec = device_addr.cast<double>("ups_per_sec", 20);
- if (ups_per_sec > 0.0){
- const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec);
- _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up);
- }
-
- //setting the packets per update (enabled by default)
- size_t send_frame_size = device.dsp_xports[0]->get_send_frame_size();
- const double ups_per_fifo = device_addr.cast<double>("ups_per_fifo", 8.0);
- if (ups_per_fifo > 0.0){
- const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/send_frame_size);
- _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up);
- }
-
- //initialize the clock configuration
- if (device_addr.has_key("mimo_mode")){
- if (device_addr["mimo_mode"] == "master"){
- _mimo_clocking_mode_is_master = true;
- }
- else if (device_addr["mimo_mode"] == "slave"){
- _mimo_clocking_mode_is_master = false;
- }
- else throw uhd::value_error(
- "mimo_mode must be set to master or slave"
- );
- }
- else {
- _mimo_clocking_mode_is_master = (_iface->peek32(U2_REG_STATUS) & (1 << 8)) != 0;
- }
- UHD_MSG(status) << boost::format("mboard%d is MIMO %s") % _index %
- (_mimo_clocking_mode_is_master?"master":"slave") << std::endl;
-
- //init the clock config
- if(_iface->mb_eeprom["gpsdo"] == "internal" or
- _iface->mb_eeprom["gpsdo"] == "external") {
- _clock_config = clock_config_t::external();
- }
- else {
- _clock_config = clock_config_t::internal();
- }
- update_clock_config();
-
- //init the codec before the dboard
- codec_init();
-
- //init the tx and rx dboards (do last)
- dboard_init();
-
- //set default subdev specs
- (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t();
- (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t();
-
- //------------------------------------------------------------------
- //This is a hack/fix for the lingering packet problem.
- stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
- for (size_t i = 0; i < NUM_RX_DSPS; i++){
- size_t index = device.dsp_xports.size() - NUM_RX_DSPS + i;
- stream_cmd.num_samps = 1;
- this->issue_ddc_stream_cmd(stream_cmd, i);
- device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for lingering
- device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for expected
- _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //resets sequence
- }
- //------------------------------------------------------------------
-
- //initialize VITA time to GPS time
- if( _gps_ctrl.get()
- and _gps_ctrl->gps_detected()) {
- UHD_MSG(status) << "Setting device time to GPS time...\n";
- set_time_spec(time_spec_t(double(_gps_ctrl->get_sensor("gps_time").to_int()+1)), false);
- }
-}
-
-usrp2_mboard_impl::~usrp2_mboard_impl(void){UHD_SAFE_CALL(
- _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, 0);
- _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, 0);
-)}
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp2_mboard_impl::update_clock_config(void){
- boost::uint32_t pps_flags = 0;
-
- //slave mode overrides clock config settings
- if (not _mimo_clocking_mode_is_master){
- _clock_config.ref_source = clock_config_t::REF_MIMO;
- _clock_config.pps_source = clock_config_t::PPS_MIMO;
- }
-
- //translate pps source enums
- switch(_clock_config.pps_source){
- case clock_config_t::PPS_MIMO:
- _iface->poke32(U2_REG_TIME64_MIMO_SYNC,
- (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff)
- );
- break;
-
- case clock_config_t::PPS_SMA:
- _iface->poke32(U2_REG_TIME64_MIMO_SYNC, 0);
- pps_flags |= U2_FLAG_TIME64_PPS_SMA;
- break;
-
- default: throw uhd::value_error("unhandled clock configuration pps source");
- }
-
- //translate pps polarity enums
- switch(_clock_config.pps_polarity){
- case clock_config_t::PPS_POS: pps_flags |= U2_FLAG_TIME64_PPS_POSEDGE; break;
- case clock_config_t::PPS_NEG: pps_flags |= U2_FLAG_TIME64_PPS_NEGEDGE; break;
- default: throw uhd::value_error("unhandled clock configuration pps polarity");
- }
-
- //set the pps flags
- _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags);
-
- //clock source ref 10mhz
- switch(_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:
- switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); break;
- case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break;
- default: throw uhd::value_error("unhandled clock configuration reference source");
- }
- _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
- break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break;
- case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break;
- default: throw uhd::value_error("unhandled clock configuration reference source");
- }
- _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT);
- break;
-
- case usrp2_iface::USRP_NXXX: break;
- }
-
- //masters always drive the clock over serdes
- _clock_ctrl->enable_mimo_clock_out(_mimo_clocking_mode_is_master);
-
- //set the mimo clock delay over the serdes
- if (_mimo_clocking_mode_is_master){
- switch(_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:
- _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
- break;
-
- case usrp2_iface::USRP2_REV4:
- _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
- break;
-
- default: break; //not handled
- }
- }
-
-}
-
-void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){
- //dont set the time for slave devices, they always take from mimo cable
- if (not _mimo_clocking_mode_is_master) return;
-
- //set the ticks
- _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq()));
-
- //set the flags register
- boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
- _iface->poke32(U2_REG_TIME64_IMM, imm_flags);
-
- //set the seconds (latches in all 3 registers)
- _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs()));
-}
-
-/***********************************************************************
- * MBoard Get Properties
- **********************************************************************/
-void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
- static const std::string dboard_name = "A";
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_NAME:
- val = _iface->get_cname() + " mboard";
- return;
-
- case MBOARD_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case MBOARD_PROP_RX_DBOARD:
- UHD_ASSERT_THROW(key.name == dboard_name or key.name == "0"); //allow for old name to work
- val = _rx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DBOARD_NAMES:
- val = prop_names_t(1, dboard_name);
- return;
-
- case MBOARD_PROP_TX_DBOARD:
- UHD_ASSERT_THROW(key.name == dboard_name or key.name == "0"); //allow for old name to work
- val = _tx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DBOARD_NAMES:
- val = prop_names_t(1, dboard_name);
- return;
-
- case MBOARD_PROP_RX_DSP:
- val = _rx_dsp_proxies[key.name]->get_link();
- return;
-
- case MBOARD_PROP_RX_DSP_NAMES:
- val = _rx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_TX_DSP:
- val = _tx_dsp_proxies[key.name]->get_link();
- return;
-
- case MBOARD_PROP_TX_DSP_NAMES:
- val = _tx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- val = _clock_config;
- return;
-
- case MBOARD_PROP_TIME_NOW: while(true){
- uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_IMM);
- uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_IMM);
- if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_IMM)) continue;
- val = time_spec_t(secs, ticks, get_master_clock_freq());
- return;
- }
-
- case MBOARD_PROP_TIME_PPS: while(true){
- uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_PPS);
- uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_PPS);
- if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_PPS)) continue;
- val = time_spec_t(secs, ticks, get_master_clock_freq());
- return;
- }
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- val = _rx_subdev_spec;
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- val = _tx_subdev_spec;
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- val = _iface->mb_eeprom;
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- val = this->get_master_clock_freq();
- return;
-
- case SUBDEV_PROP_SENSOR_NAMES:{
- prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked");
- if (_gps_ctrl.get()) {
- std::vector<std::string> gs = _gps_ctrl->get_sensors();
- names.insert(names.end(), gs.begin(), gs.end());
- }
- val = names;
- }
- return;
-
- case MBOARD_PROP_SENSOR:
- if(key.name == "mimo_locked") {
- val = sensor_value_t("MIMO", this->get_mimo_locked(), "locked", "unlocked");
- return;
- }
- else if(key.name == "ref_locked") {
- val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked");
- return;
- }
- else if(uhd::has(_gps_ctrl->get_sensors(), key.name) and _gps_ctrl.get()) {
- val = _gps_ctrl->get_sensor(key.name);
- }
- else {
- UHD_THROW_PROP_GET_ERROR();
- }
- break;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-bool usrp2_mboard_impl::get_mimo_locked(void) {
- return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<10)) > 0);
-}
-
-bool usrp2_mboard_impl::get_ref_locked(void) {
- return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<11)) > 0);
-}
-
-/***********************************************************************
- * MBoard Set Properties
- **********************************************************************/
-void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
- //handle the set request conditioned on the key
- switch(key.as<mboard_prop_t>()){
-
- case MBOARD_PROP_CLOCK_CONFIG:
- _clock_config = val.as<clock_config_t>();
- update_clock_config();
- return;
-
- case MBOARD_PROP_TIME_NOW:
- set_time_spec(val.as<time_spec_t>(), true);
- return;
-
- case MBOARD_PROP_TIME_PPS:
- set_time_spec(val.as<time_spec_t>(), false);
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:{
- _rx_subdev_spec = val.as<subdev_spec_t>();
- verify_rx_subdev_spec(_rx_subdev_spec, this->get_link());
- //sanity check
- UHD_ASSERT_THROW(_rx_subdev_spec.size() <= NUM_RX_DSPS);
-
- //determine frontend swap IQ from the first channel
- bool fe_swap_iq = false;
- switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(0).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
- case SUBDEV_CONN_COMPLEX_QI:
- case SUBDEV_CONN_REAL_Q:
- fe_swap_iq = true;
- break;
- default: fe_swap_iq = false;
- }
- _iface->poke32(U2_REG_RX_FE_SWAP_IQ, fe_swap_iq? 1 : 0);
-
- //set the dsp mux for each channel
- for (size_t i = 0; i < _rx_subdev_spec.size(); i++){
- bool iq_swap = false, real_mode = false;
- switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(i).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
- case SUBDEV_CONN_COMPLEX_IQ:
- iq_swap = fe_swap_iq;
- real_mode = false;
- break;
- case SUBDEV_CONN_COMPLEX_QI:
- iq_swap = not fe_swap_iq;
- real_mode = false;
- break;
- case SUBDEV_CONN_REAL_I:
- iq_swap = fe_swap_iq;
- real_mode = true;
- break;
- case SUBDEV_CONN_REAL_Q:
- iq_swap = not fe_swap_iq;
- real_mode = true;
- break;
- }
- _iface->poke32(U2_REG_DSP_RX_MUX(i),
- (iq_swap? U2_FLAG_DSP_RX_MUX_SWAP_IQ : 0) |
- (real_mode? U2_FLAG_DSP_RX_MUX_REAL_MODE : 0)
- );
- }
- _device.update_xport_channel_mapping();
- }return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- _tx_subdev_spec = val.as<subdev_spec_t>();
- verify_tx_subdev_spec(_tx_subdev_spec, this->get_link());
- //sanity check
- UHD_ASSERT_THROW(_tx_subdev_spec.size() <= NUM_TX_DSPS);
- //set the mux
- for (size_t i = 0; i < _rx_subdev_spec.size(); i++){
- _iface->poke32(U2_REG_TX_FE_MUX, dsp_type1::calc_tx_mux_word(
- _dboard_manager->get_tx_subdev(_tx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
- ));
- }
- _device.update_xport_channel_mapping();
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- // Step1: commit the map, writing only those values set.
- // Step2: readback the entire eeprom map into the iface.
- val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_N100);
- _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_N100);
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- UHD_ASSERT_THROW(val.as<double>() == this->get_master_clock_freq());
- _device.update_xport_channel_mapping();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 6ba364b28..0db9e5d58 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -160,24 +160,24 @@ public:
/***********************************************************************
* Peek and Poke
**********************************************************************/
- void poke32(boost::uint32_t addr, boost::uint32_t data){
+ void poke32(wb_addr_type addr, boost::uint32_t data){
this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_POKE32>(addr, data);
}
- boost::uint32_t peek32(boost::uint32_t addr){
+ boost::uint32_t peek32(wb_addr_type addr){
return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr);
}
- void poke16(boost::uint32_t addr, boost::uint16_t data){
+ void poke16(wb_addr_type addr, boost::uint16_t data){
this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_POKE16>(addr, data);
}
- boost::uint16_t peek16(boost::uint32_t addr){
+ boost::uint16_t peek16(wb_addr_type addr){
return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr);
}
template <class T, usrp2_reg_action_t action>
- T get_reg(boost::uint32_t addr, T data = 0){
+ T get_reg(wb_addr_type addr, T data = 0){
//setup the out data
usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
out_data.id = htonl(USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO);
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 16b640a70..f36febce4 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -19,15 +19,14 @@
#define INCLUDED_USRP2_IFACE_HPP
#include <uhd/transport/udp_simple.hpp>
-#include <uhd/usrp/mboard_iface.hpp>
+#include <uhd/types/serial.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include <boost/cstdint.hpp>
#include <boost/function.hpp>
-#include <utility>
-#include <string>
#include "usrp2_regs.hpp"
-
+#include "wb_iface.hpp"
+#include <string>
//TODO: kill this crap when you have the top level GPS include file
typedef boost::function<void(std::string)> gps_send_fn_t;
@@ -38,7 +37,7 @@ typedef boost::function<std::string(void)> gps_recv_fn_t;
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp2_iface : public uhd::usrp::mboard_iface, boost::noncopyable{
+class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
/*!
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index aa584ac8b..e00924ebd 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -22,18 +22,18 @@
#include <uhd/exception.hpp>
#include <uhd/transport/if_addrs.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
-#include <uhd/usrp/device_props.hpp>
+#include <uhd/types/ranges.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/byteswap.hpp>
-#include <boost/assign/list_of.hpp>
+#include <uhd/utils/safe_call.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio.hpp> //used for htonl and ntohl
-#include <vector>
using namespace uhd;
using namespace uhd::usrp;
@@ -227,6 +227,23 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u
}
/***********************************************************************
+ * Helpers
+ **********************************************************************/
+static void init_xport(zero_copy_if::sptr xport){
+ //Send a small data packet so the usrp2 knows the udp source port.
+ //This setup must happen before further initialization occurs
+ //or the async update packets will cause ICMP destination unreachable.
+ static const boost::uint32_t data[2] = {
+ uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
+ uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
+ };
+
+ transport::managed_send_buffer::sptr send_buff = xport->get_send_buff();
+ std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ send_buff->commit(sizeof(data));
+}
+
+/***********************************************************************
* Structors
**********************************************************************/
usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
@@ -272,67 +289,385 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
device_args = separate_device_addr(device_addr); //update args for new frame sizes
- //setup rx otw type
- _rx_otw_type.width = 16;
- _rx_otw_type.shift = 0;
- _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+ ////////////////////////////////////////////////////////////////////
+ // create controller objects and initialize the properties tree
+ ////////////////////////////////////////////////////////////////////
+ _tree = property_tree::make();
+ _tree->create<std::string>("/name").set("USRP2 / N-Series Device");
+
+ for (size_t mbi = 0; mbi < device_args.size(); mbi++){
+ const device_addr_t device_args_i = device_args[mbi];
+ const std::string mb = boost::lexical_cast<std::string>(mbi);
+ const std::string addr = device_args_i["addr"];
+ property_tree::path_type mb_path = "/mboards/" + mb;
+
+ ////////////////////////////////////////////////////////////////
+ // construct transports for dsp and async errors
+ ////////////////////////////////////////////////////////////////
+ UHD_LOG << "Making transport for DSP0..." << std::endl;
+ _mbc[mb].dsp_xports.push_back(udp_zero_copy::make(
+ addr, BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_args_i
+ ));
+ init_xport(_mbc[mb].dsp_xports.back());
- //setup tx otw type
- _tx_otw_type.width = 16;
- _tx_otw_type.shift = 0;
- _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+ UHD_LOG << "Making transport for DSP1..." << std::endl;
+ _mbc[mb].dsp_xports.push_back(udp_zero_copy::make(
+ addr, BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_args_i
+ ));
+ init_xport(_mbc[mb].dsp_xports.back());
- //!!!!! set the otw type here before continuing, its used below
+ UHD_LOG << "Making transport for ERR0..." << std::endl;
+ _mbc[mb].err_xports.push_back(udp_zero_copy::make(
+ addr, BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t()
+ ));
+ init_xport(_mbc[mb].err_xports.back());
- //create a new mboard handler for each control transport
- for(size_t i = 0; i < device_args.size(); i++){
- device_addr_t dev_addr_i = device_args[i];
- BOOST_FOREACH(const std::string &key, device_addr.keys()){
- if (dev_addr_i.has_key(key)) continue;
- dev_addr_i[key] = device_addr[key];
+ ////////////////////////////////////////////////////////////////
+ // create the iface that controls i2c, spi, uart, and wb
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].iface = usrp2_iface::make(udp_simple::make_connected(
+ addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
+ ));
+ _tree->create<std::string>(mb_path / "name").set(_mbc[mb].iface->get_cname());
+
+ ////////////////////////////////////////////////////////////////
+ // setup the mboard eeprom
+ ////////////////////////////////////////////////////////////////
+ _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ .set(_mbc[mb].iface->mb_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1));
+
+ ////////////////////////////////////////////////////////////////
+ // create clock control objects
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface);
+ _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));
+
+ ////////////////////////////////////////////////////////////////
+ // create codec control objects
+ ////////////////////////////////////////////////////////////////
+ property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A";
+ property_tree::path_type 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);
+ 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<std::string>(rx_codec_path / "name").set("ads62p44");
+ _tree->create<meta_range_t>(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5));
+ _tree->create<double>(rx_codec_path / "gains/digital/value")
+ .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0);
+ _tree->create<meta_range_t>(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05));
+ _tree->create<double>(rx_codec_path / "gains/fine/value")
+ .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mbc[mb].codec, _1)).set(0);
+ }break;
+
+ case usrp2_iface::USRP2_REV3:
+ case usrp2_iface::USRP2_REV4:
+ _tree->create<std::string>(rx_codec_path / "name").set("ltc2284");
+ break;
+
+ case usrp2_iface::USRP_NXXX:
+ _tree->create<std::string>(rx_codec_path / "name").set("??????");
+ break;
+ }
+ _tree->create<std::string>(tx_codec_path / "name").set("ad9777");
+
+ ////////////////////////////////////////////////////////////////
+ // create gpsdo control objects
+ ////////////////////////////////////////////////////////////////
+ if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){
+ _mbc[mb].gps = gps_ctrl::make(
+ _mbc[mb].iface->get_gps_write_fn(),
+ _mbc[mb].iface->get_gps_read_fn()
+ );
+ BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){
+ _tree->create<sensor_value_t>(mb_path / "sensors" / name)
+ .publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name));
+ }
}
- _mboards.push_back(usrp2_mboard_impl::sptr(
- new usrp2_mboard_impl(dev_addr_i, i, *this)
+
+ ////////////////////////////////////////////////////////////////
+ // and do the misc mboard sensors
+ ////////////////////////////////////////////////////////////////
+ _tree->create<sensor_value_t>(mb_path / "sensors/mimo_locked")
+ .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb));
+ _tree->create<sensor_value_t>(mb_path / "sensors/ref_locked")
+ .publish(boost::bind(&usrp2_impl::get_ref_locked, this, mb));
+
+ ////////////////////////////////////////////////////////////////
+ // 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].tx_fe = tx_frontend_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT)
+ );
+ //TODO lots of properties to expose here for frontends
+ _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .subscribe(boost::bind(&usrp2_impl::update_rx_subdev_spec, this, mb, _1));
+ _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .subscribe(boost::bind(&usrp2_impl::update_tx_subdev_spec, this, mb, _1));
+
+ ////////////////////////////////////////////////////////////////
+ // 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].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
));
- //use an empty name when there is only one mboard
- std::string name = (device_args.size() > 1)? boost::lexical_cast<std::string>(i) : "";
- _mboard_dict[name] = _mboards.back();
+ for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _mbc[mb].rx_dsps[dspno], _1));
+ //This is a hack/fix for the lingering packet problem.
+ //The dsp core starts streaming briefly... now we flush
+ _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for lingering
+ _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for expected
+ property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<double>(rx_dsp_path / "rate/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _mbc[mb].rx_dsps[dspno], _1))
+ .subscribe(boost::bind(&usrp2_impl::update_rx_samp_rate, this, _1));
+ _tree->create<double>(rx_dsp_path / "freq/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1));
+ _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
+ .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno]));
+ _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd")
+ .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _mbc[mb].rx_dsps[dspno], _1));
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // 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
+ );
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/rate/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1))
+ .subscribe(boost::bind(&usrp2_impl::update_tx_samp_rate, this, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/freq/value")
+ .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1));
+ _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
+ .publish(boost::bind(&usrp2_impl::get_tx_dsp_freq_range, this, mb));
+
+ //setup dsp flow control
+ const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20);
+ const size_t send_frame_size = _mbc[mb].dsp_xports.front()->get_send_frame_size();
+ const double ups_per_fifo = device_args_i.cast<double>("ups_per_fifo", 8.0);
+ _mbc[mb].tx_dsp->set_updates(
+ (ups_per_sec > 0.0)? size_t(100e6/*approx tick rate*//ups_per_sec) : 0,
+ (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0
+ );
+
+ ////////////////////////////////////////////////////////////////
+ // create time control objects
+ ////////////////////////////////////////////////////////////////
+ time64_core_200::readback_bases_type time64_rb_bases;
+ time64_rb_bases.rb_secs_imm = U2_REG_TIME64_SECS_RB_IMM;
+ time64_rb_bases.rb_ticks_imm = U2_REG_TIME64_TICKS_RB_IMM;
+ time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS;
+ time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_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
+ );
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/now")
+ .publish(boost::bind(&time64_core_200::get_time_now, _mbc[mb].time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_now, _mbc[mb].time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/pps")
+ .publish(boost::bind(&time64_core_200::get_time_last_pps, _mbc[mb].time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1));
+ //setup time source props
+ _tree->create<std::string>(mb_path / "time_source/value")
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1));
+ _tree->create<std::vector<std::string> >(mb_path / "time_source/options")
+ .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64));
+ //setup reference source props
+ _tree->create<std::string>(mb_path / "ref_source/value")
+ .subscribe(boost::bind(&usrp2_impl::update_ref_source, this, mb, _1));
+ static const std::vector<std::string> ref_sources = boost::assign::list_of("internal")("sma")("mimo");
+ _tree->create<std::vector<std::string> >(mb_path / "ref_source/options").set(ref_sources);
+
+ ////////////////////////////////////////////////////////////////
+ // create dboard control objects
+ ////////////////////////////////////////////////////////////////
+
+ //read the dboard eeprom to extract the dboard ids
+ dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
+ rx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
+ tx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
+ gdb_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
+
+ //create the properties and register subscribers
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom")
+ .set(rx_db_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom")
+ .set(tx_db_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom")
+ .set(gdb_eeprom)
+ .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);
+ _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,
+ ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
+ _mbc[mb].dboard_iface
+ );
+ BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_rx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree, mb_path / "dboards/A/rx_frontends" / name,
+ _mbc[mb].dboard_manager->get_rx_subdev(name)
+ );
+ }
+ BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_tx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree, mb_path / "dboards/A/tx_frontends" / name,
+ _mbc[mb].dboard_manager->get_tx_subdev(name)
+ );
+ }
}
- //init the send and recv io
- io_init();
+ //initialize io handling
+ this->io_init();
+
+ //do some post-init tasks
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ property_tree::path_type root = "/mboards/" + mb;
+ _tree->access<double>(root / "tick_rate").update();
+
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(root / "rx_dsps")){
+ _tree->access<double>(root / "rx_dsps" / name / "rate" / "value").set(1e6);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){
+ _tree->access<double>(root / "tx_dsps" / name / "rate" / "value").set(1e6);
+ }
+
+ _tree->access<subdev_spec_t>(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0]));
+ _tree->access<subdev_spec_t>(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0]));
+ _tree->access<std::string>(root / "ref_source/value").set("internal");
+ _tree->access<std::string>(root / "time_source/value").set("none");
+
+ //GPS installed: use external ref, time, and init time spec
+ if (_mbc[mb].gps.get() != NULL){
+ _tree->access<std::string>(root / "time_source/value").set("sma");
+ _tree->access<std::string>(root / "ref_source/value").set("sma");
+ _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1)));
+ }
+ }
}
-usrp2_impl::~usrp2_impl(void){
- /* NOP */
+usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ _mbc[mb].tx_dsp->set_updates(0, 0);
+ }
+)}
+
+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);
}
-/***********************************************************************
- * Device Properties
- **********************************************************************/
-void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
+void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
+ if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
+ if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
+ if (type == "gdb") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
+}
- //handle the get request conditioned on the key
- switch(key.as<device_prop_t>()){
- case DEVICE_PROP_NAME:
- if (_mboards.size() > 1) val = std::string("USRP2/N Series multi-device");
- else val = std::string("USRP2/N Series device");
- return;
+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;
+ return sensor_value_t("MIMO", lock, "locked", "unlocked");
+}
- case DEVICE_PROP_MBOARD:
- val = _mboard_dict[key.name]->get_link();
- return;
+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;
+ return sensor_value_t("Ref", lock, "locked", "unlocked");
+}
- case DEVICE_PROP_MBOARD_NAMES:
- val = prop_names_t(_mboard_dict.keys());
- return;
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
- default: UHD_THROW_PROP_GET_ERROR();
- }
+double usrp2_impl::set_tx_dsp_freq(const std::string &mb, const double freq_){
+ double new_freq = freq_;
+ const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
+
+ //calculate the DAC shift (multiples of rate)
+ const int sign = boost::math::sign(new_freq);
+ const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2);
+ const double dac_shift = sign*zone*tick_rate;
+ new_freq -= dac_shift; //update FPGA DSP target freq
+
+ //set the DAC shift (modulation mode)
+ if (zone == 0) _mbc[mb].codec->set_tx_mod_mode(0); //no shift
+ else _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
+
+ return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq
}
-void usrp2_impl::set(const wax::obj &, const wax::obj &){
- UHD_THROW_PROP_SET_ERROR();
+meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){
+ const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
+ const meta_range_t dsp_range = _mbc[mb].tx_dsp->get_freq_range();
+ return meta_range_t(dsp_range.start() - tick_rate*2, dsp_range.stop() + tick_rate*2, dsp_range.step());
+}
+
+void usrp2_impl::update_ref_source(const std::string &mb, const std::string &source){
+ //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);
+ else if (source == "sma") _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);
+ _mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
+ break;
+
+ case usrp2_iface::USRP2_REV3:
+ case usrp2_iface::USRP2_REV4:
+ if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);
+ else if (source == "sma") _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);
+ _mbc[mb].clock->enable_external_ref(source != "internal");
+ break;
+
+ case usrp2_iface::USRP_NXXX: break;
+ }
+
+ //always drive the clock over serdes if not locking to it
+ _mbc[mb].clock->enable_mimo_clock_out(source != "mimo");
+
+ //set the mimo clock delay over the serdes
+ if (source != "mimo"){
+ 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].clock->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
+ break;
+
+ case usrp2_iface::USRP2_REV4:
+ _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
+ break;
+
+ default: break; //not handled
+ }
+ }
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 4d19863b1..ad203079b 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -21,6 +21,12 @@
#include "usrp2_iface.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
+#include "rx_frontend_core_200.hpp"
+#include "tx_frontend_core_200.hpp"
+#include "rx_dsp_core_200.hpp"
+#include "tx_dsp_core_200.hpp"
+#include "time64_core_200.hpp"
+#include <uhd/property_tree.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/device.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -37,6 +43,13 @@
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_spec.hpp>
+static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
+static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
+static const size_t mimo_clock_sync_delay_cycles = 137;
+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;
+
/*!
* Make a usrp2 dboard interface.
* \param iface the usrp2 interface object
@@ -49,139 +62,13 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
);
/*!
- * Simple wax obj proxy class:
- * Provides a wax obj interface for a set and a get function.
- * This allows us to create nested properties structures
- * while maintaining flattened code within the implementation.
- */
-class wax_obj_proxy : public wax::obj{
-public:
- typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
- typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
- typedef boost::shared_ptr<wax_obj_proxy> sptr;
-
- static sptr make(const get_t &get, const set_t &set){
- return sptr(new wax_obj_proxy(get, set));
- }
-
-private:
- get_t _get; set_t _set;
- wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){};
- void get(const wax::obj &key, wax::obj &val){return _get(key, val);}
- void set(const wax::obj &key, const wax::obj &val){return _set(key, val);}
-};
-
-class usrp2_impl;
-
-/*!
- * USRP2 mboard implementation guts:
- * The implementation details are encapsulated here.
- * Handles properties on the mboard, dboard, dsps...
- */
-class usrp2_mboard_impl : public wax::obj{
-public:
- typedef boost::shared_ptr<usrp2_mboard_impl> sptr;
-
- static const size_t NUM_RX_DSPS = 2;
- static const size_t NUM_TX_DSPS = 1;
- static const size_t MAX_NUM_DSPS = 2;
-
- //structors
- usrp2_mboard_impl(
- const uhd::device_addr_t &device_addr,
- size_t index, usrp2_impl &device
- );
- ~usrp2_mboard_impl(void);
-
- inline double get_master_clock_freq(void){
- return _clock_ctrl->get_master_clock_rate();
- }
-
- void handle_overflow(size_t);
-
-private:
- size_t _index;
- usrp2_impl &_device;
- bool _mimo_clocking_mode_is_master;
-
- //interfaces
- usrp2_iface::sptr _iface;
- usrp2_clock_ctrl::sptr _clock_ctrl;
- usrp2_codec_ctrl::sptr _codec_ctrl;
- gps_ctrl::sptr _gps_ctrl;
-
- //properties for this mboard
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
- uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
-
- //rx and tx dboard methods and objects
- uhd::usrp::dboard_manager::sptr _dboard_manager;
- uhd::usrp::dboard_iface::sptr _dboard_iface;
- void dboard_init(void);
-
- //methods and shadows for clock configuration
- uhd::clock_config_t _clock_config;
- void update_clock_config(void);
- void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
-
- //properties interface for the codec
- void codec_init(void);
- void rx_codec_get(const wax::obj &, wax::obj &);
- void rx_codec_set(const wax::obj &, const wax::obj &);
- void tx_codec_get(const wax::obj &, wax::obj &);
- void tx_codec_set(const wax::obj &, const wax::obj &);
- wax_obj_proxy::sptr _rx_codec_proxy;
- wax_obj_proxy::sptr _tx_codec_proxy;
-
- void rx_codec_set_gain(double, const std::string &);
- uhd::dict<std::string, double> _codec_rx_gains;
-
- //properties interface for rx dboard
- void rx_dboard_get(const wax::obj &, wax::obj &);
- void rx_dboard_set(const wax::obj &, const wax::obj &);
- wax_obj_proxy::sptr _rx_dboard_proxy;
- uhd::usrp::dboard_eeprom_t _rx_db_eeprom;
-
- //properties interface for tx dboard
- void tx_dboard_get(const wax::obj &, wax::obj &);
- void tx_dboard_set(const wax::obj &, const wax::obj &);
- wax_obj_proxy::sptr _tx_dboard_proxy;
- uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
-
- //methods and shadows for the dsps
- UHD_PIMPL_DECL(dsp_impl) _dsp_impl;
- void dsp_init(void);
- void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t);
-
- //properties interface for ddc
- void ddc_get(const wax::obj &, wax::obj &, size_t);
- void ddc_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies;
-
- //properties interface for duc
- void duc_get(const wax::obj &, wax::obj &, size_t);
- void duc_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies;
-
- //sensors methods for mboard
- bool get_mimo_locked(void);
- bool get_ref_locked(void);
-};
-
-/*!
* USRP2 implementation guts:
* The implementation details are encapsulated here.
* Handles device properties and streaming...
*/
class usrp2_impl : public uhd::device{
public:
- static const size_t sram_bytes = size_t(1 << 20);
- static const boost::uint32_t RECV_SID = 1;
- static const boost::uint32_t ASYNC_SID = 2;
-
usrp2_impl(const uhd::device_addr_t &);
-
~usrp2_impl(void);
//the io interface
@@ -199,27 +86,49 @@ public:
size_t get_max_recv_samps_per_packet(void) const;
bool recv_async_msg(uhd::async_metadata_t &, double);
- void update_xport_channel_mapping(void);
-
- //public frame sizes, set by mboard, used by io impl
- size_t recv_frame_size, send_frame_size;
-
- std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports;
- std::vector<uhd::transport::zero_copy_if::sptr> err_xports;
-
private:
- //device properties interface
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
+ uhd::property_tree::sptr _tree;
+ struct mb_container_type{
+ usrp2_iface::sptr iface;
+ usrp2_clock_ctrl::sptr clock;
+ usrp2_codec_ctrl::sptr codec;
+ gps_ctrl::sptr gps;
+ rx_frontend_core_200::sptr rx_fe;
+ tx_frontend_core_200::sptr tx_fe;
+ std::vector<rx_dsp_core_200::sptr> rx_dsps;
+ tx_dsp_core_200::sptr tx_dsp;
+ time64_core_200::sptr time64;
+ std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports;
+ std::vector<uhd::transport::zero_copy_if::sptr> err_xports;
+ uhd::usrp::dboard_manager::sptr dboard_manager;
+ uhd::usrp::dboard_iface::sptr dboard_iface;
+ size_t rx_chan_occ, tx_chan_occ;
+ };
+ uhd::dict<std::string, mb_container_type> _mbc;
+
+ void set_mb_eeprom(const std::string &, const uhd::usrp::mboard_eeprom_t &);
+ void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &);
+
+ uhd::sensor_value_t get_mimo_locked(const std::string &);
+ uhd::sensor_value_t get_ref_locked(const std::string &);
- //pointers to mboards on this device (think mimo setup)
- std::vector<usrp2_mboard_impl::sptr> _mboards;
- uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict;
+ //device properties interface
+ void get(const wax::obj &, wax::obj &val){
+ val = _tree; //entry point into property tree
+ }
//io impl methods and members
uhd::otw_type_t _rx_otw_type, _tx_otw_type;
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
+ void update_tick_rate(const double rate);
+ void update_rx_samp_rate(const double rate);
+ void update_tx_samp_rate(const double rate);
+ void update_rx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
+ void update_tx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
+ double set_tx_dsp_freq(const std::string &, const double);
+ uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);
+ void update_ref_source(const std::string &, const std::string &);
};
#endif /* INCLUDED_USRP2_IMPL_HPP */
diff --git a/host/lib/usrp2/CMakeLists.txt b/host/lib/usrp2/CMakeLists.txt
deleted file mode 100644
index d16976060..000000000
--- a/host/lib/usrp2/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright 2011 Ettus Research LLC
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-########################################################################
-# This file included, use CMake directory variables
-########################################################################
-LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
-)
diff --git a/host/lib/usrp2/clock_ctrl.cpp b/host/lib/usrp2/clock_ctrl.cpp
deleted file mode 100644
index 66c7a6c28..000000000
--- a/host/lib/usrp2/clock_ctrl.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "clock_ctrl.hpp"
-#include "ad9510_regs.hpp"
-#include "usrp2_regs.hpp" //spi slave constants
-#include "usrp2_clk_regs.hpp"
-#include <uhd/utils/safe_call.hpp>
-#include <uhd/utils/assert_has.hpp>
-#include <boost/cstdint.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <iostream>
-
-using namespace uhd;
-
-static const bool enb_test_clk = false;
-
-/*!
- * A usrp2 clock control specific to the ad9510 ic.
- */
-class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{
-public:
- usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
- clk_regs = usrp2_clk_regs_t(_iface->get_rev());
-
- _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
- this->write_reg(clk_regs.pll_3);
-
- // 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(clk_regs.pll_4);
-
- _ad9510_regs.acounter = 0;
- this->write_reg(clk_regs.acounter);
-
- _ad9510_regs.bcounter_msb = 0;
- _ad9510_regs.bcounter_lsb = 5;
- this->write_reg(clk_regs.bcounter_msb);
- this->write_reg(clk_regs.bcounter_lsb);
-
- _ad9510_regs.ref_counter_msb = 0;
- _ad9510_regs.ref_counter_lsb = 1; // r divider = 1
- this->write_reg(clk_regs.ref_counter_msb);
- this->write_reg(clk_regs.ref_counter_lsb);
-
- /* regs will be updated in commands below */
-
- this->enable_external_ref(false);
- this->enable_rx_dboard_clock(false);
- this->enable_tx_dboard_clock(false);
- this->enable_mimo_clock_out(false);
-
- /* private clock enables, must be set here */
- this->enable_dac_clock(true);
- this->enable_adc_clock(true);
- this->enable_test_clock(enb_test_clk);
- }
-
- ~usrp2_clock_ctrl_impl(void){UHD_SAFE_CALL(
- //power down clock outputs
- this->enable_external_ref(false);
- this->enable_rx_dboard_clock(false);
- this->enable_tx_dboard_clock(false);
- this->enable_dac_clock(false);
- this->enable_adc_clock(false);
- this->enable_mimo_clock_out(false);
- this->enable_test_clock(false);
- )}
-
- void enable_mimo_clock_out(bool enb){
- //calculate the low and high dividers
- size_t divider = size_t(this->get_master_clock_rate()/10e6);
- size_t high = divider/2;
- size_t low = divider - high;
-
- switch(clk_regs.exp){
- case 2: //U2 rev 3
- _ad9510_regs.power_down_lvpecl_out2 = enb?
- ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL :
- ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD;
- _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_810MV;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out2 = low - 1;
- _ad9510_regs.divider_high_cycles_out2 = high - 1;
- _ad9510_regs.bypass_divider_out2 = 0;
- break;
-
- case 5: //U2 rev 4
- _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_LVDS;
- _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out5 = low - 1;
- _ad9510_regs.divider_high_cycles_out5 = high - 1;
- _ad9510_regs.bypass_divider_out5 = 0;
- break;
-
- case 6: //U2+
- _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_LVDS;
- _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out6 = low - 1;
- _ad9510_regs.divider_high_cycles_out6 = high - 1;
- _ad9510_regs.bypass_divider_out5 = 0;
- break;
-
- default:
- break;
- }
- this->write_reg(clk_regs.output(clk_regs.exp));
- this->write_reg(clk_regs.div_lo(clk_regs.exp));
- this->update_regs();
- }
-
- //uses output clock 7 (cmos)
- void enable_rx_dboard_clock(bool enb){
- switch(_iface->get_rev()) {
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_LVDS;
- _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
- this->write_reg(clk_regs.output(clk_regs.rx_db));
- this->update_regs();
- break;
- default:
- _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(clk_regs.output(clk_regs.rx_db));
- this->update_regs();
- break;
- }
- }
-
- void set_rate_rx_dboard_clock(double rate){
- assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate");
- size_t divider = size_t(get_master_clock_rate()/rate);
- //bypass when the divider ratio is one
- _ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0;
- //calculate the low and high dividers
- size_t high = divider/2;
- size_t low = divider - high;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out7 = low - 1;
- _ad9510_regs.divider_high_cycles_out7 = high - 1;
- //write the registers
- this->write_reg(clk_regs.div_lo(clk_regs.rx_db));
- this->write_reg(clk_regs.div_hi(clk_regs.rx_db));
- this->update_regs();
- }
-
- std::vector<double> get_rates_rx_dboard_clock(void){
- std::vector<double> rates;
- for (size_t i = 1; i <= 16+16; i++) rates.push_back(get_master_clock_rate()/i);
- return rates;
- }
-
- //uses output clock 6 (cmos) on USRP2 and output clock 5 (cmos) on USRP2+
- void enable_tx_dboard_clock(bool enb){
- switch(clk_regs.tx_db) {
- case 5: //USRP2+
- _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_CMOS;
- _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA;
- break;
- case 6: //USRP2
- _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;
- break;
- }
-
- this->write_reg(clk_regs.output(clk_regs.tx_db));
- this->update_regs();
- }
-
- void set_rate_tx_dboard_clock(double rate){
- assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate");
- size_t divider = size_t(get_master_clock_rate()/rate);
- //bypass when the divider ratio is one
- _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
- //calculate the low and high dividers
- size_t high = divider/2;
- size_t low = divider - high;
-
- switch(clk_regs.tx_db) {
- case 5: //USRP2+
- _ad9510_regs.bypass_divider_out5 = (divider == 1)? 1 : 0;
- _ad9510_regs.divider_low_cycles_out5 = low - 1;
- _ad9510_regs.divider_high_cycles_out5 = high - 1;
- break;
- case 6: //USRP2
- //bypass when the divider ratio is one
- _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out6 = low - 1;
- _ad9510_regs.divider_high_cycles_out6 = high - 1;
- break;
- }
-
- //write the registers
- this->write_reg(clk_regs.div_hi(clk_regs.tx_db));
- this->write_reg(clk_regs.div_lo(clk_regs.tx_db));
- this->update_regs();
- }
-
- std::vector<double> get_rates_tx_dboard_clock(void){
- return get_rates_rx_dboard_clock(); //same master clock, same dividers...
- }
-
- void enable_test_clock(bool enb) {
- _ad9510_regs.power_down_lvpecl_out0 = enb?
- ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_NORMAL :
- ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_SAFE_PD;
- _ad9510_regs.output_level_lvpecl_out0 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT0_810MV;
- _ad9510_regs.divider_low_cycles_out0 = 0;
- _ad9510_regs.divider_high_cycles_out0 = 0;
- _ad9510_regs.bypass_divider_out0 = 1;
- this->write_reg(0x3c);
- this->write_reg(0x48);
- this->write_reg(0x49);
- }
-
- /*!
- * 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(clk_regs.pll_2);
- this->update_regs();
- }
-
- double get_master_clock_rate(void){
- return 100e6;
- }
-
- void set_mimo_clock_delay(double delay) {
- //delay_val is a 5-bit value (0-31) for fine control
- //the equations below determine delay for a given ramp current, # of caps and fine delay register
- //delay range:
- //range_ns = 200*((caps+3)/i_ramp_ua)*1.3286
- //offset (zero delay):
- //offset_ns = 0.34 + (1600 - i_ramp_ua)*1e-4 + ((caps-1)/ramp)*6
- //delay_ns = offset_ns + range_ns * delay / 31
-
- int delay_val = boost::math::iround(delay/9.744e-9*31);
-
- if(delay_val == 0) {
- switch(clk_regs.exp) {
- case 5:
- _ad9510_regs.delay_control_out5 = 1;
- break;
- case 6:
- _ad9510_regs.delay_control_out6 = 1;
- break;
- default:
- break; //delay not supported on U2 rev 3
- }
- } else {
- switch(clk_regs.exp) {
- case 5:
- _ad9510_regs.delay_control_out5 = 0;
- _ad9510_regs.ramp_current_out5 = ad9510_regs_t::RAMP_CURRENT_OUT5_200UA;
- _ad9510_regs.ramp_capacitor_out5 = ad9510_regs_t::RAMP_CAPACITOR_OUT5_4CAPS;
- _ad9510_regs.delay_fine_adjust_out5 = delay_val;
- this->write_reg(0x34);
- this->write_reg(0x35);
- this->write_reg(0x36);
- break;
- case 6:
- _ad9510_regs.delay_control_out6 = 0;
- _ad9510_regs.ramp_current_out6 = ad9510_regs_t::RAMP_CURRENT_OUT6_200UA;
- _ad9510_regs.ramp_capacitor_out6 = ad9510_regs_t::RAMP_CAPACITOR_OUT6_4CAPS;
- _ad9510_regs.delay_fine_adjust_out6 = delay_val;
- this->write_reg(0x38);
- this->write_reg(0x39);
- this->write_reg(0x3A);
- break;
- default:
- break;
- }
- }
- }
-
-private:
- /*!
- * 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->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24);
- }
-
- /*!
- * Tells the ad9510 to latch the settings into the operational registers.
- */
- void update_regs(void){
- _ad9510_regs.update_registers = 1;
- this->write_reg(clk_regs.update);
- }
-
- //uses output clock 3 (pecl)
- //this is the same between USRP2 and USRP2+ and doesn't get a switch statement
- 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;
- _ad9510_regs.bypass_divider_out3 = 1;
- this->write_reg(clk_regs.output(clk_regs.dac));
- this->write_reg(clk_regs.div_hi(clk_regs.dac));
- this->update_regs();
- }
-
- //uses output clock 4 (lvds) on USRP2 and output clock 2 (lvpecl) on USRP2+
- void enable_adc_clock(bool enb){
- switch(clk_regs.adc) {
- case 2:
- _ad9510_regs.power_down_lvpecl_out2 = enb? ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD;
- _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_500MV;
- _ad9510_regs.bypass_divider_out2 = 1;
- break;
- case 4:
- _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;
- _ad9510_regs.bypass_divider_out4 = 1;
- break;
- }
-
- this->write_reg(clk_regs.output(clk_regs.adc));
- this->write_reg(clk_regs.div_hi(clk_regs.adc));
- this->update_regs();
- }
-
- usrp2_iface::sptr _iface;
-
- usrp2_clk_regs_t clk_regs;
- ad9510_regs_t _ad9510_regs;
-};
-
-/***********************************************************************
- * 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));
-}
diff --git a/host/lib/usrp2/clock_ctrl.hpp b/host/lib/usrp2/clock_ctrl.hpp
deleted file mode 100644
index 9ccbc959e..000000000
--- a/host/lib/usrp2/clock_ctrl.hpp
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_CLOCK_CTRL_HPP
-#define INCLUDED_CLOCK_CTRL_HPP
-
-#include "usrp2_iface.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <vector>
-
-class usrp2_clock_ctrl : boost::noncopyable{
-public:
- typedef boost::shared_ptr<usrp2_clock_ctrl> 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(usrp2_iface::sptr iface);
-
- /*!
- * Get the master clock frequency for the fpga.
- * \return the clock frequency in Hz
- */
- virtual double get_master_clock_rate(void) = 0;
-
- /*!
- * Enable/disable the rx dboard clock.
- * \param enb true to enable
- */
- virtual void enable_rx_dboard_clock(bool enb) = 0;
-
- /*!
- * Set the clock rate on the rx dboard clock.
- * \param rate the new clock rate
- * \throw exception when rate invalid
- */
- virtual void set_rate_rx_dboard_clock(double rate) = 0;
-
- /*!
- * Get a list of possible rx dboard clock rates.
- * \return a list of clock rates in Hz
- */
- virtual std::vector<double> get_rates_rx_dboard_clock(void) = 0;
-
- /*!
- * Enable/disable the tx dboard clock.
- * \param enb true to enable
- */
- virtual void enable_tx_dboard_clock(bool enb) = 0;
-
- /*!
- * Set the clock rate on the tx dboard clock.
- * \param rate the new clock rate
- * \throw exception when rate invalid
- */
- virtual void set_rate_tx_dboard_clock(double rate) = 0;
-
- /*!
- * Get a list of possible tx dboard clock rates.
- * \return a list of clock rates in Hz
- */
- virtual std::vector<double> get_rates_tx_dboard_clock(void) = 0;
-
- /*!
- * Enable/disable external reference.
- * \param enb true to enable
- */
- virtual void enable_external_ref(bool enb) = 0;
-
- /*!
- * Enable/disable test clock output.
- * \param enb true to enable
- */
- virtual void enable_test_clock(bool enb) = 0;
-
- /*!
- * Enable/disable the ref clock output over the serdes cable.
- * \param enb true to enable
- */
- virtual void enable_mimo_clock_out(bool enb) = 0;
-
- /*!
- * Set the output delay of the mimo clock
- * Used to synchronise daisy-chained USRPs over the MIMO cable
- * Can also be used to adjust delay for uneven reference cable lengths
- * \param delay the clock delay in seconds
- */
- virtual void set_mimo_clock_delay(double delay) = 0;
-
-};
-
-#endif /* INCLUDED_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp2/codec_ctrl.cpp b/host/lib/usrp2/codec_ctrl.cpp
deleted file mode 100644
index 06bf83b15..000000000
--- a/host/lib/usrp2/codec_ctrl.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "codec_ctrl.hpp"
-#include "ad9777_regs.hpp"
-#include "ads62p44_regs.hpp"
-#include "usrp2_regs.hpp"
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhd/exception.hpp>
-#include <boost/cstdint.hpp>
-#include <boost/foreach.hpp>
-
-using namespace uhd;
-
-/*!
- * A usrp2 codec control specific to the ad9777 ic.
- */
-class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{
-public:
- usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
-
- //setup the ad9777 dac
- _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_COMPLEX;
- _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
- _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_ON;
- _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_AUTO;
- //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++){
- this->send_ad9777_reg(addr);
- }
- set_tx_mod_mode(0);
-
- //power-up adc
- switch(_iface->get_rev()){
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_ON);
- break;
-
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- _ads62p44_regs.reset = 1;
- this->send_ads62p44_reg(0x00); //issue a reset to the ADC
- //everything else should be pretty much default, i think
- //_ads62p44_regs.decimation = DECIMATION_DECIMATE_1;
- _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_NORMAL;
- this->send_ads62p44_reg(0x14);
- this->set_rx_analog_gain(1);
- break;
-
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- _ads62p44_regs.reset = 1;
- this->send_ads62p44_reg(0x00); //issue a reset to the ADC
- //everything else should be pretty much default, i think
- //_ads62p44_regs.decimation = DECIMATION_DECIMATE_1;
- _ads62p44_regs.override = 1;
- this->send_ads62p44_reg(0x14);
- _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_NORMAL;
- _ads62p44_regs.output_interface = ads62p44_regs_t::OUTPUT_INTERFACE_LVDS;
- _ads62p44_regs.lvds_current = ads62p44_regs_t::LVDS_CURRENT_2_5MA;
- _ads62p44_regs.lvds_data_term = ads62p44_regs_t::LVDS_DATA_TERM_100;
- this->send_ads62p44_reg(0x11);
- this->send_ads62p44_reg(0x12);
- this->send_ads62p44_reg(0x14);
- this->set_rx_analog_gain(1);
- break;
-
- case usrp2_iface::USRP_NXXX: break;
- }
- }
-
- ~usrp2_codec_ctrl_impl(void){UHD_SAFE_CALL(
- //power-down dac
- _ad9777_regs.power_down_mode = 1;
- this->send_ad9777_reg(0);
-
- //power-down adc
- switch(_iface->get_rev()){
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_OFF);
- break;
-
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- //send a global power-down to the ADC here... it will get lifted on reset
- _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_GLOBAL_PD;
- this->send_ads62p44_reg(0x14);
- break;
-
- case usrp2_iface::USRP_NXXX: break;
- }
- )}
-
- void set_tx_mod_mode(int mod_mode){
- //set the sign of the frequency shift
- _ad9777_regs.modulation_form = (mod_mode > 0)?
- ad9777_regs_t::MODULATION_FORM_E_PLUS_JWT:
- ad9777_regs_t::MODULATION_FORM_E_MINUS_JWT
- ;
-
- //set the frequency shift
- switch(std::abs(mod_mode)){
- case 0:
- case 1: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_NONE; break;
- case 2: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_2; break;
- case 4: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_4; break;
- case 8: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_8; break;
- default: throw uhd::value_error("unknown modulation mode for ad9777");
- }
-
- this->send_ad9777_reg(0x01); //set the register
- }
-
- void set_rx_digital_gain(double gain) { //fine digital gain
- switch(_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:
- _ads62p44_regs.fine_gain = int(gain/0.5);
- this->send_ads62p44_reg(0x17);
- break;
-
- default: UHD_THROW_INVALID_CODE_PATH();
- }
- }
-
- void set_rx_digital_fine_gain(double gain) { //gain correction
- switch(_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:
- _ads62p44_regs.gain_correction = int(gain / 0.05);
- this->send_ads62p44_reg(0x1A);
- break;
-
- default: UHD_THROW_INVALID_CODE_PATH();
- }
- }
-
- void set_rx_analog_gain(bool /*gain*/) { //turns on/off analog 3.5dB preamp
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- _ads62p44_regs.coarse_gain = ads62p44_regs_t::COARSE_GAIN_3_5DB;//gain ? ads62p44_regs_t::COARSE_GAIN_3_5DB : ads62p44_regs_t::COARSE_GAIN_0DB;
- this->send_ads62p44_reg(0x14);
- break;
-
- default: UHD_THROW_INVALID_CODE_PATH();
- }
- }
-
-private:
- ad9777_regs_t _ad9777_regs;
- ads62p44_regs_t _ads62p44_regs;
- usrp2_iface::sptr _iface;
-
- 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(
- SPI_SS_AD9777, spi_config_t::EDGE_RISE,
- reg, 16
- );
- }
-
- void send_ads62p44_reg(boost::uint8_t addr) {
- boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr);
- _iface->write_spi(
- SPI_SS_ADS62P44, spi_config_t::EDGE_FALL,
- reg, 16
- );
- }
-};
-
-/***********************************************************************
- * 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));
-}
diff --git a/host/lib/usrp2/codec_ctrl.hpp b/host/lib/usrp2/codec_ctrl.hpp
deleted file mode 100644
index ca300e2b1..000000000
--- a/host/lib/usrp2/codec_ctrl.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_CODEC_CTRL_HPP
-#define INCLUDED_CODEC_CTRL_HPP
-
-#include "usrp2_iface.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-
-class usrp2_codec_ctrl : boost::noncopyable{
-public:
- typedef boost::shared_ptr<usrp2_codec_ctrl> sptr;
-
- /*!
- * Make a codec control for the DAC and ADC.
- * \param _iface a pointer to the usrp2 interface object
- * \return a new codec control object
- */
- static sptr make(usrp2_iface::sptr iface);
-
- /*!
- * Set the modulation mode for the DAC.
- * Possible modes are 0, +/-1, +/-2, +/-4, +/-8
- * which correspond to shifts of fs/mod_mode.
- * A mode of 0 or +/-1 means no modulation.
- * \param mod_mode the modulation mode
- */
- virtual void set_tx_mod_mode(int mod_mode) = 0;
-
- /*!
- * Set the analog preamplifier on the USRP2+ ADC (ADS62P44).
- * \param gain enable or disable the 3.5dB preamp
- */
-
- virtual void set_rx_analog_gain(bool gain) = 0;
-
- /*!
- * Set the digital gain on the USRP2+ ADC (ADS62P44).
- * \param gain from 0-6dB
- */
-
- virtual void set_rx_digital_gain(double gain) = 0;
-
- /*!
- * Set the digital gain correction on the USRP2+ ADC (ADS62P44).
- * \param gain from 0-0.5dB
- */
-
- virtual void set_rx_digital_fine_gain(double gain) = 0;
-
-};
-
-#endif /* INCLUDED_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp2/dboard_iface.cpp b/host/lib/usrp2/dboard_iface.cpp
deleted file mode 100644
index 4ce49b409..000000000
--- a/host/lib/usrp2/dboard_iface.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_ctrl.hpp"
-#include "usrp2_regs.hpp" //wishbone address constants
-#include <uhd/usrp/dboard_iface.hpp>
-#include <uhd/types/dict.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/asio.hpp> //htonl and ntohl
-#include <boost/math/special_functions/round.hpp>
-#include "ad7922_regs.hpp" //aux adc
-#include "ad5623_regs.hpp" //aux dac
-
-using namespace uhd;
-using namespace uhd::usrp;
-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(void);
-
- special_props_t get_special_props(void){
- special_props_t props;
- props.soft_clock_divider = false;
- props.mangle_i2c_addrs = false;
- return props;
- }
-
- void write_aux_dac(unit_t, aux_dac_t, double);
- double read_aux_adc(unit_t, aux_adc_t);
-
- void _set_pin_ctrl(unit_t, boost::uint16_t);
- void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
- void _set_gpio_ddr(unit_t, boost::uint16_t);
- void _set_gpio_out(unit_t, boost::uint16_t);
- void set_gpio_debug(unit_t, int);
- boost::uint16_t read_gpio(unit_t);
-
- void write_i2c(boost::uint8_t, const byte_vector_t &);
- byte_vector_t read_i2c(boost::uint8_t, size_t);
-
- void set_clock_rate(unit_t, double);
- double get_clock_rate(unit_t);
- std::vector<double> get_clock_rates(unit_t);
- void set_clock_enabled(unit_t, bool);
- double get_codec_rate(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;
- usrp2_clock_ctrl::sptr _clock_ctrl;
- boost::uint32_t _ddr_shadow;
- boost::uint32_t _gpio_shadow;
-
- uhd::dict<unit_t, ad5623_regs_t> _dac_regs;
- uhd::dict<unit_t, double> _clock_rates;
- void _write_aux_dac(unit_t);
-};
-
-/***********************************************************************
- * Make Function
- **********************************************************************/
-dboard_iface::sptr make_usrp2_dboard_iface(
- usrp2_iface::sptr iface,
- usrp2_clock_ctrl::sptr clock_ctrl
-){
- return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_dboard_iface::usrp2_dboard_iface(
- usrp2_iface::sptr iface,
- usrp2_clock_ctrl::sptr clock_ctrl
-){
- _iface = iface;
- _clock_ctrl = clock_ctrl;
- _ddr_shadow = 0;
- _gpio_shadow = 0;
-
- //reset the aux dacs
- _dac_regs[UNIT_RX] = ad5623_regs_t();
- _dac_regs[UNIT_TX] = ad5623_regs_t();
- BOOST_FOREACH(unit_t unit, _dac_regs.keys()){
- _dac_regs[unit].data = 1;
- _dac_regs[unit].addr = ad5623_regs_t::ADDR_ALL;
- _dac_regs[unit].cmd = ad5623_regs_t::CMD_RESET;
- this->_write_aux_dac(unit);
- }
-
- //init the clock rate shadows with max rate clock
- this->set_clock_rate(UNIT_RX, sorted(this->get_clock_rates(UNIT_RX)).back());
- this->set_clock_rate(UNIT_TX, sorted(this->get_clock_rates(UNIT_TX)).back());
-}
-
-usrp2_dboard_iface::~usrp2_dboard_iface(void){
- /* NOP */
-}
-
-/***********************************************************************
- * Clocks
- **********************************************************************/
-void usrp2_dboard_iface::set_clock_rate(unit_t unit, double rate){
- _clock_rates[unit] = rate; //set to shadow
- switch(unit){
- case UNIT_RX: _clock_ctrl->set_rate_rx_dboard_clock(rate); return;
- case UNIT_TX: _clock_ctrl->set_rate_tx_dboard_clock(rate); return;
- }
-}
-
-double usrp2_dboard_iface::get_clock_rate(unit_t unit){
- return _clock_rates[unit]; //get from shadow
-}
-
-std::vector<double> usrp2_dboard_iface::get_clock_rates(unit_t unit){
- switch(unit){
- case UNIT_RX: return _clock_ctrl->get_rates_rx_dboard_clock();
- case UNIT_TX: return _clock_ctrl->get_rates_tx_dboard_clock();
- default: UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
- switch(unit){
- case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return;
- case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return;
- }
-}
-
-double usrp2_dboard_iface::get_codec_rate(unit_t){
- return _clock_ctrl->get_master_clock_rate();
-}
-/***********************************************************************
- * GPIO
- **********************************************************************/
-static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
- (dboard_iface::UNIT_RX, 0)
- (dboard_iface::UNIT_TX, 16)
-;
-
-void usrp2_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){
- //calculate the new selection mux setting
- boost::uint32_t new_sels = 0x0;
- for(size_t i = 0; i < 16; i++){
- bool is_bit_set = (value & (0x1 << i)) != 0;
- new_sels |= ((is_bit_set)? U2_FLAG_GPIO_SEL_ATR : U2_FLAG_GPIO_SEL_GPIO) << (i*2);
- }
-
- //write the selection mux value to register
- switch(unit){
- case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
- case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
- }
-}
-
-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(U2_REG_GPIO_DDR, _ddr_shadow);
-}
-
-void usrp2_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){
- _gpio_shadow = \
- (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) |
- (boost::uint32_t(value) << unit_to_shift[unit]);
- _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow);
-}
-
-boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
- return boost::uint16_t(_iface->peek32(U2_REG_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 = map_list_of
- (UNIT_RX, map_list_of
- (ATR_REG_IDLE, U2_REG_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE)
- )
- (UNIT_TX, map_list_of
- (ATR_REG_IDLE, U2_REG_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE)
- )
- ;
- _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
-}
-
-void usrp2_dboard_iface::set_gpio_debug(unit_t unit, int which){
- this->set_gpio_ddr(unit, 0xffff); //all outputs
-
- //calculate the new selection mux setting
- boost::uint32_t new_sels = 0x0;
- int sel = (which == 0)?
- U2_FLAG_GPIO_SEL_DEBUG_0:
- U2_FLAG_GPIO_SEL_DEBUG_1;
- for(size_t i = 0; i < 16; i++){
- new_sels |= sel << (i*2);
- }
-
- //write the selection mux value to register
- switch(unit){
- case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
- case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
- }
-}
-
-/***********************************************************************
- * SPI
- **********************************************************************/
-static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of
- (dboard_iface::UNIT_TX, SPI_SS_TX_DB)
- (dboard_iface::UNIT_RX, SPI_SS_RX_DB)
-;
-
-void usrp2_dboard_iface::write_spi(
- unit_t unit,
- const spi_config_t &config,
- boost::uint32_t data,
- size_t num_bits
-){
- _iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits);
-}
-
-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->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);
-}
-
-byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
- return _iface->read_i2c(addr, num_bytes);
-}
-
-/***********************************************************************
- * Aux DAX/ADC
- **********************************************************************/
-void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
- static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of
- (UNIT_RX, SPI_SS_RX_DAC)
- (UNIT_TX, SPI_SS_TX_DAC)
- ;
- _iface->write_spi(
- unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,
- _dac_regs[unit].get_reg(), 24
- );
-}
-
-void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, double value){
- _dac_regs[unit].data = boost::math::iround(4095*value/3.3);
- _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N;
-
- typedef uhd::dict<aux_dac_t, ad5623_regs_t::addr_t> aux_dac_to_addr;
- static const uhd::dict<unit_t, aux_dac_to_addr> unit_to_which_to_addr = map_list_of
- (UNIT_RX, map_list_of
- (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_B)
- (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_A)
- (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_A)
- (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_B)
- )
- (UNIT_TX, map_list_of
- (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_A)
- (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_B)
- (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_B)
- (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_A)
- )
- ;
- _dac_regs[unit].addr = unit_to_which_to_addr[unit][which];
- this->_write_aux_dac(unit);
-}
-
-double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
- static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
- (UNIT_RX, SPI_SS_RX_ADC)
- (UNIT_TX, SPI_SS_TX_ADC)
- ;
-
- //setup spi config args
- spi_config_t config;
- config.mosi_edge = spi_config_t::EDGE_FALL;
- config.miso_edge = spi_config_t::EDGE_RISE;
-
- //setup the spi registers
- ad7922_regs_t ad7922_regs;
- switch(which){
- case AUX_ADC_A: ad7922_regs.mod = 0; break;
- case AUX_ADC_B: ad7922_regs.mod = 1; break;
- } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn
-
- //write and read 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(
- unit_to_spi_adc[unit], config,
- ad7922_regs.get_reg(), 16
- )));
-
- //convert to voltage and return
- return 3.3*ad7922_regs.result/4095;
-}
diff --git a/host/lib/usrp2/fw_common.h b/host/lib/usrp2/fw_common.h
deleted file mode 100644
index 21abc6aed..000000000
--- a/host/lib/usrp2/fw_common.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_FW_COMMON_H
-#define INCLUDED_USRP2_FW_COMMON_H
-
-#include <stdint.h>
-
-/*!
- * Structs and constants for usrp2 communication.
- * This header is shared by the firmware and host code.
- * Therefore, this header may only contain valid C code.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 7
-#define USRP2_FW_COMPAT_NUM 10
-
-//used to differentiate control packets over data port
-#define USRP2_INVALID_VRT_HEADER 0
-
-// udp ports for the usrp2 communication
-// Dynamic and/or private ports: 49152-65535
-#define USRP2_UDP_CTRL_PORT 49152
-//#define USRP2_UDP_UPDATE_PORT 49154
-#define USRP2_UDP_DSP0_PORT 49156
-#define USRP2_UDP_ERR0_PORT 49157
-#define USRP2_UDP_DSP1_PORT 49158
-
-////////////////////////////////////////////////////////////////////////
-// I2C addresses
-////////////////////////////////////////////////////////////////////////
-#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
-#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0)
-#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4)
-#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5)
-
-////////////////////////////////////////////////////////////////////////
-// EEPROM Layout
-////////////////////////////////////////////////////////////////////////
-#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_IP_ADDR 0x0C //uint32, big-endian
-#define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7
-
-typedef enum{
- USRP2_CTRL_ID_HUH_WHAT = ' ',
- //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
- //USRP2_CTRL_ID_SUX_MAN,
-
- USRP2_CTRL_ID_WAZZUP_BRO = 'a',
- USRP2_CTRL_ID_WAZZUP_DUDE = 'A',
-
- USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's',
- USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S',
-
- USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO = 'i',
- USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE = 'I',
-
- USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',
- USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H',
-
- USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO = 'r',
- USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE = 'R',
-
- USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO = 'u',
- USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE = 'U',
-
- USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO = 'v',
- USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE = 'V',
-
- USRP2_CTRL_ID_HOLLER_AT_ME_BRO = 'l',
- USRP2_CTRL_ID_HOLLER_BACK_DUDE = 'L',
-
- USRP2_CTRL_ID_PEACE_OUT = '~'
-
-} usrp2_ctrl_id_t;
-
-typedef enum{
- USRP2_DIR_RX = 'r',
- USRP2_DIR_TX = 't'
-} usrp2_dir_which_t;
-
-typedef enum{
- USRP2_CLK_EDGE_RISE = 'r',
- USRP2_CLK_EDGE_FALL = 'f'
-} usrp2_clk_edge_t;
-
-typedef enum{
- USRP2_REG_ACTION_FPGA_PEEK32 = 1,
- USRP2_REG_ACTION_FPGA_PEEK16 = 2,
- USRP2_REG_ACTION_FPGA_POKE32 = 3,
- USRP2_REG_ACTION_FPGA_POKE16 = 4,
- USRP2_REG_ACTION_FW_PEEK32 = 5,
- USRP2_REG_ACTION_FW_POKE32 = 6
-} usrp2_reg_action_t;
-
-typedef struct{
- uint32_t proto_ver;
- uint32_t id;
- uint32_t seq;
- union{
- uint32_t ip_addr;
- struct {
- uint32_t dev;
- uint32_t data;
- uint8_t miso_edge;
- uint8_t mosi_edge;
- uint8_t num_bits;
- uint8_t readback;
- } spi_args;
- struct {
- uint8_t addr;
- uint8_t bytes;
- uint8_t data[20];
- } i2c_args;
- struct {
- uint32_t addr;
- uint32_t data;
- uint8_t action;
- } reg_args;
- struct {
- uint8_t dev;
- uint8_t bytes;
- uint8_t data[20];
- } uart_args;
- struct {
- uint32_t len;
- } echo_args;
- } data;
-} usrp2_ctrl_data_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* INCLUDED_USRP2_FW_COMMON_H */
diff --git a/host/lib/usrp2/io_impl.cpp b/host/lib/usrp2/io_impl.cpp
deleted file mode 100644
index 64c099ff6..000000000
--- a/host/lib/usrp2/io_impl.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "../../transport/super_recv_packet_handler.hpp"
-#include "../../transport/super_send_packet_handler.hpp"
-#include "usrp2_impl.hpp"
-#include "usrp2_regs.hpp"
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/thread_priority.hpp>
-#include <uhd/transport/bounded_buffer.hpp>
-#include <boost/format.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
-#include <iostream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-namespace asio = boost::asio;
-namespace pt = boost::posix_time;
-
-/***********************************************************************
- * helpers
- **********************************************************************/
-static UHD_INLINE pt::time_duration to_time_dur(double timeout){
- return pt::microseconds(long(timeout*1e6));
-}
-
-static UHD_INLINE double from_time_dur(const pt::time_duration &time_dur){
- return 1e-6*time_dur.total_microseconds();
-}
-
-/***********************************************************************
- * constants
- **********************************************************************/
-static const int underflow_flags = 0
- | async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET
-;
-
-static const size_t vrt_send_header_offset_words32 = 1;
-
-/***********************************************************************
- * flow control monitor for a single tx channel
- * - the pirate thread calls update
- * - the get send buffer calls check
- **********************************************************************/
-class flow_control_monitor{
-public:
- typedef boost::uint32_t seq_type;
- typedef boost::shared_ptr<flow_control_monitor> sptr;
-
- /*!
- * Make a new flow control monitor.
- * \param max_seqs_out num seqs before throttling
- */
- flow_control_monitor(seq_type max_seqs_out){
- _last_seq_out = 0;
- _last_seq_ack = 0;
- _max_seqs_out = max_seqs_out;
- _ready_fcn = boost::bind(&flow_control_monitor::ready, this);
- }
-
- /*!
- * Gets the current sequence number to go out.
- * Increments the sequence for the next call
- * \return the sequence to be sent to the dsp
- */
- UHD_INLINE seq_type get_curr_seq_out(void){
- return _last_seq_out++;
- }
-
- /*!
- * Check the flow control condition.
- * \param timeout the timeout in seconds
- * \return false on timeout
- */
- UHD_INLINE bool check_fc_condition(double timeout){
- boost::mutex::scoped_lock lock(_fc_mutex);
- if (this->ready()) return true;
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return _fc_cond.timed_wait(lock, to_time_dur(timeout), _ready_fcn);
- }
-
- /*!
- * Update the flow control condition.
- * \param seq the last sequence number to be ACK'd
- */
- UHD_INLINE void update_fc_condition(seq_type seq){
- boost::mutex::scoped_lock lock(_fc_mutex);
- _last_seq_ack = seq;
- lock.unlock();
- _fc_cond.notify_one();
- }
-
-private:
- bool ready(void){
- return seq_type(_last_seq_out -_last_seq_ack) < _max_seqs_out;
- }
-
- boost::mutex _fc_mutex;
- boost::condition _fc_cond;
- seq_type _last_seq_out, _last_seq_ack, _max_seqs_out;
- boost::function<bool(void)> _ready_fcn;
-};
-
-/***********************************************************************
- * io impl details (internal to this file)
- * - pirate crew
- * - alignment buffer
- * - thread loop
- * - vrt packet handler states
- **********************************************************************/
-struct usrp2_impl::io_impl{
-
- io_impl(void):
- async_msg_fifo(100/*messages deep*/)
- {
- /* NOP */
- }
-
- ~io_impl(void){
- recv_pirate_crew.interrupt_all();
- recv_pirate_crew.join_all();
- }
-
- managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){
- flow_control_monitor &fc_mon = *fc_mons[chan];
-
- //wait on flow control w/ timeout
- if (not fc_mon.check_fc_condition(timeout)) return managed_send_buffer::sptr();
-
- //get a buffer from the transport w/ timeout
- managed_send_buffer::sptr buff = tx_xports[chan]->get_send_buff(timeout);
-
- //write the flow control word into the buffer
- if (buff.get()) buff->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_mon.get_curr_seq_out());
-
- return buff;
- }
-
- //tx dsp: xports and flow control monitors
- std::vector<zero_copy_if::sptr> tx_xports;
- std::vector<flow_control_monitor::sptr> fc_mons;
-
- //state management for the vrt packet handler code
- sph::recv_packet_handler recv_handler;
- sph::send_packet_handler send_handler;
-
- //methods and variables for the pirate crew
- void recv_pirate_loop(boost::barrier &, zero_copy_if::sptr, size_t);
- boost::thread_group recv_pirate_crew;
- bounded_buffer<async_metadata_t> async_msg_fifo;
- double tick_rate;
-};
-
-/***********************************************************************
- * Receive Pirate Loop
- * - while raiding, loot for message packet
- * - update flow control condition count
- * - put async message packets into queue
- **********************************************************************/
-void usrp2_impl::io_impl::recv_pirate_loop(
- boost::barrier &spawn_barrier,
- zero_copy_if::sptr err_xport,
- size_t index
-){
- spawn_barrier.wait();
- set_thread_priority_safe();
-
- //store a reference to the flow control monitor (offset by max dsps)
- flow_control_monitor &fc_mon = *(this->fc_mons[index]);
-
- while (not boost::this_thread::interruption_requested()){
- managed_recv_buffer::sptr buff = err_xport->get_recv_buff();
- if (not buff.get()) continue; //ignore timeout/error buffers
-
- try{
- //extract the vrt header packet info
- vrt::if_packet_info_t if_packet_info;
- if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
- const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
- vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
-
- //handle a tx async report message
- if (if_packet_info.sid == USRP2_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
-
- //fill in the async metadata
- async_metadata_t metadata;
- metadata.channel = index;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
-
- //catch the flow control packets and react
- if (metadata.event_code == 0){
- boost::uint32_t fc_word32 = (vrt_hdr + if_packet_info.num_header_words32)[1];
- fc_mon.update_fc_condition(uhd::ntohx(fc_word32));
- continue;
- }
-
- //print the famous U, and push the metadata into the message queue
- if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U";
- //else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl;
- async_msg_fifo.push_with_pop_on_full(metadata);
- }
- else{
- //TODO unknown received packet, may want to print error...
- }
- }catch(const std::exception &e){
- UHD_MSG(error) << "Error (usrp2 recv pirate loop): " << e.what() << std::endl;
- }
- }
-}
-
-/***********************************************************************
- * Helper Functions
- **********************************************************************/
-void usrp2_impl::io_init(void){
-
- //setup rx otw type
- _rx_otw_type.width = 16;
- _rx_otw_type.shift = 0;
- _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
-
- //setup tx otw type
- _tx_otw_type.width = 16;
- _tx_otw_type.shift = 0;
- _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
-
- //create new io impl
- _io_impl = UHD_PIMPL_MAKE(io_impl, ());
-
- //init first so we dont have an access race
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- //init the tx xport and flow control monitor
- _io_impl->tx_xports.push_back(_mbc[mb].dsp_xports.at(0));
- _io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
- USRP2_SRAM_BYTES/_mbc[mb].dsp_xports.at(0)->get_send_frame_size()
- )));
- }
-
- //create a new pirate thread for each zc if (yarr!!)
- boost::barrier spawn_barrier(_mbc.size()+1);
- size_t index = 0;
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- //spawn a new pirate to plunder the recv booty
- _io_impl->recv_pirate_crew.create_thread(boost::bind(
- &usrp2_impl::io_impl::recv_pirate_loop,
- _io_impl.get(), boost::ref(spawn_barrier),
- _mbc[mb].err_xports.at(0), index++
- ));
- }
- spawn_barrier.wait();
-
- //init some handler stuff
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be);
- _io_impl->recv_handler.set_converter(_rx_otw_type);
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32);
- _io_impl->send_handler.set_converter(_tx_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
-}
-
-void usrp2_impl::update_tick_rate(const double rate){
- _io_impl->tick_rate = rate;
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.set_tick_rate(rate);
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.set_tick_rate(rate);
-}
-
-void usrp2_impl::update_rx_samp_rate(const double rate){
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.set_samp_rate(rate);
-}
-
-void usrp2_impl::update_tx_samp_rate(const double rate){
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.set_samp_rate(rate);
-}
-
-void usrp2_impl::update_rx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
-
- //sanity checking
- if (spec.size() == 0) throw uhd::value_error("rx subdev spec cant be empty");
- if (spec.size() > _mbc[which_mb].rx_dsps.size()) throw uhd::value_error("rx subdev spec too long");
-
- //setup mux for this spec
- for (size_t i = 0; i < spec.size(); i++){
- //ASSUME that we dont swap the rx fe mux...
- const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get();
- _mbc[which_mb].rx_dsps[i]->set_mux(conn);
- }
-
- //compute the new occupancy and resize
- _mbc[which_mb].rx_chan_occ = spec.size();
- size_t nchan = 0;
- BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].rx_chan_occ;
- _io_impl->recv_handler.resize(nchan);
-
- //bind new callbacks for the handler
- size_t chan = 0;
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- for (size_t dsp = 0; dsp < _mbc[mb].rx_chan_occ; dsp++){
- _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
- _io_impl->recv_handler.set_xport_chan_get_buff(chan++, boost::bind(
- &zero_copy_if::get_recv_buff, _mbc[mb].dsp_xports[dsp], _1
- ));
- }
- }
-}
-
-void usrp2_impl::update_tx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
-
- //sanity checking
- if (spec.size() != 1) throw uhd::value_error("tx subdev spec has to be size 1");
-
- //set the mux for this spec
- const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
- _mbc[which_mb].tx_fe->set_mux(conn);
-
- //compute the new occupancy and resize
- _mbc[which_mb].tx_chan_occ = spec.size();
- size_t nchan = 0;
- BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].tx_chan_occ;
- _io_impl->send_handler.resize(nchan);
-
- //bind new callbacks for the handler
- size_t chan = 0, i = 0;
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- for (size_t dsp = 0; dsp < _mbc[mb].tx_chan_occ; dsp++){
- _io_impl->send_handler.set_xport_chan_get_buff(chan++, boost::bind(
- &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), i++, _1
- ));
- }
- }
-}
-
-/***********************************************************************
- * Async Data
- **********************************************************************/
-bool usrp2_impl::recv_async_msg(
- async_metadata_t &async_metadata, double timeout
-){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
-}
-
-/***********************************************************************
- * Send Data
- **********************************************************************/
-size_t usrp2_impl::get_max_send_samps_per_packet(void) const{
- static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + vrt_send_header_offset_words32*sizeof(boost::uint32_t)
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- ;
- const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_send_frame_size() - hdr_size;
- return bpp/_tx_otw_type.get_sample_size();
-}
-
-size_t usrp2_impl::send(
- const send_buffs_type &buffs, size_t nsamps_per_buff,
- const tx_metadata_t &metadata, const io_type_t &io_type,
- send_mode_t send_mode, double timeout
-){
- return _io_impl->send_handler.send(
- buffs, nsamps_per_buff,
- metadata, io_type,
- send_mode, timeout
- );
-}
-
-/***********************************************************************
- * Receive Data
- **********************************************************************/
-size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{
- static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- ;
- const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_recv_frame_size() - hdr_size;
- return bpp/_rx_otw_type.get_sample_size();
-}
-
-size_t usrp2_impl::recv(
- const recv_buffs_type &buffs, size_t nsamps_per_buff,
- rx_metadata_t &metadata, const io_type_t &io_type,
- recv_mode_t recv_mode, double timeout
-){
- return _io_impl->recv_handler.recv(
- buffs, nsamps_per_buff,
- metadata, io_type,
- recv_mode, timeout
- );
-}
diff --git a/host/lib/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp2/usrp2_clk_regs.hpp
deleted file mode 100644
index 8b185eac0..000000000
--- a/host/lib/usrp2/usrp2_clk_regs.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_USRP2_CLK_REGS_HPP
-#define INCLUDED_USRP2_CLK_REGS_HPP
-
-#include "usrp2_iface.hpp"
-
-class usrp2_clk_regs_t {
-public:
- usrp2_clk_regs_t(void) { ; }
- usrp2_clk_regs_t(usrp2_iface::rev_type rev) {
- test = 0;
- fpga = 1;
- dac = 3;
-
- switch(rev) {
- case usrp2_iface::USRP2_REV3:
- exp = 2;
- adc = 4;
- serdes = 2;
- tx_db = 6;
- break;
- case usrp2_iface::USRP2_REV4:
- exp = 5;
- adc = 4;
- serdes = 2;
- tx_db = 6;
- break;
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- exp = 6;
- adc = 2;
- serdes = 4;
- tx_db = 5;
- break;
- case usrp2_iface::USRP_NXXX:
- //dont throw, it may be unitialized
- break;
- }
-
- rx_db = 7;
- }
-
- static int output(int clknum) { return 0x3C + clknum; }
- static int div_lo(int clknum) { return 0x48 + 2 * clknum; }
- static int div_hi(int clknum) { return 0x49 + 2 * clknum; }
-
- const static int acounter = 0x04;
- const static int bcounter_msb = 0x05;
- const static int bcounter_lsb = 0x06;
- const static int pll_1 = 0x07;
- const static int pll_2 = 0x08;
- const static int pll_3 = 0x09;
- const static int pll_4 = 0x0A;
- const static int ref_counter_msb = 0x0B;
- const static int ref_counter_lsb = 0x0C;
- const static int pll_5 = 0x0D;
- const static int update = 0x5A;
-
- int test;
- int fpga;
- int adc;
- int dac;
- int serdes;
- int exp;
- int tx_db;
- int rx_db;
-};
-
-#endif //INCLUDED_USRP2_CLK_REGS_HPP
diff --git a/host/lib/usrp2/usrp2_iface.cpp b/host/lib/usrp2/usrp2_iface.cpp
deleted file mode 100644
index 0db9e5d58..000000000
--- a/host/lib/usrp2/usrp2_iface.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "fw_common.h"
-#include "usrp2_iface.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/types/dict.hpp>
-#include <boost/thread.hpp>
-#include <boost/foreach.hpp>
-#include <boost/asio.hpp> //used for htonl and ntohl
-#include <boost/assign/list_of.hpp>
-#include <boost/format.hpp>
-#include <boost/tokenizer.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
-#include <boost/functional/hash.hpp>
-#include <algorithm>
-#include <iostream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-static const double CTRL_RECV_TIMEOUT = 1.0;
-
-static const boost::uint32_t MIN_PROTO_COMPAT_SPI = 7;
-static const boost::uint32_t MIN_PROTO_COMPAT_I2C = 7;
-// The register compat number must reflect the protocol compatibility
-// and the compatibility of the register mapping (more likely to change).
-static const boost::uint32_t MIN_PROTO_COMPAT_REG = USRP2_FW_COMPAT_NUM;
-static const boost::uint32_t MIN_PROTO_COMPAT_UART = 7;
-
-// Map for virtual firmware regs (not very big so we can keep it here for now)
-#define U2_FW_REG_LOCK_TIME 0
-#define U2_FW_REG_LOCK_GPID 1
-
-//Define get_gpid() to get a globally unique identifier for this process.
-//The gpid is implemented as a hash of the pid and a unique machine identifier.
-#ifdef UHD_PLATFORM_WIN32
-#include <Windows.h>
-static inline size_t get_gpid(void){
- //extract volume serial number
- char szVolName[MAX_PATH+1], szFileSysName[MAX_PATH+1];
- DWORD dwSerialNumber, dwMaxComponentLen, dwFileSysFlags;
- GetVolumeInformation("C:\\", szVolName, MAX_PATH,
- &dwSerialNumber, &dwMaxComponentLen,
- &dwFileSysFlags, szFileSysName, sizeof(szFileSysName));
-
- size_t hash = 0;
- boost::hash_combine(hash, GetCurrentProcessId());
- boost::hash_combine(hash, dwSerialNumber);
- return hash;
-}
-#else
-#include <unistd.h>
-static inline size_t get_gpid(void){
- size_t hash = 0;
- boost::hash_combine(hash, getpid());
- boost::hash_combine(hash, gethostid());
- return hash;
-}
-#endif
-
-class usrp2_iface_impl : public usrp2_iface{
-public:
-/***********************************************************************
- * Structors
- **********************************************************************/
- usrp2_iface_impl(udp_simple::sptr ctrl_transport):
- _ctrl_transport(ctrl_transport),
- _ctrl_seq_num(0),
- _protocol_compat(0) //initialized below...
- {
- //Obtain the firmware's compat number.
- //Save the response compat number for communication.
- //TODO can choose to reject certain older compat numbers
- usrp2_ctrl_data_t ctrl_data;
- ctrl_data.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
- ctrl_data = ctrl_send_and_recv(ctrl_data, 0, ~0);
- if (ntohl(ctrl_data.id) != USRP2_CTRL_ID_WAZZUP_DUDE)
- 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);
- }
-
- ~usrp2_iface_impl(void){
- this->lock_device(false);
- }
-
-/***********************************************************************
- * Device locking
- **********************************************************************/
-
- void lock_device(bool lock){
- if (lock){
- boost::barrier spawn_barrier(2);
- _lock_thread_group.create_thread(boost::bind(&usrp2_iface_impl::lock_loop, this, boost::ref(spawn_barrier)));
- spawn_barrier.wait();
- }
- else{
- _lock_thread_group.interrupt_all();
- _lock_thread_group.join_all();
- }
- }
-
- bool is_device_locked(void){
- boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME);
- boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID);
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
-
- //if the difference is larger, assume not locked anymore
- if (curr_secs - lock_secs >= 3) return false;
-
- //otherwise only lock if the device hash is different that ours
- return lock_gpid != boost::uint32_t(get_gpid());
- }
-
- void lock_loop(boost::barrier &spawn_barrier){
- spawn_barrier.wait();
-
- try{
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid()));
- while(true){
- //re-lock in loop
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs);
- //sleep for a bit
- boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
- }
- }
- catch(const boost::thread_interrupted &){
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock on exit
- }
- catch(const std::exception &e){
- UHD_MSG(error)
- << "An unexpected exception was caught in the locker loop." << std::endl
- << "The device will automatically unlock from this process." << std::endl
- << e.what() << std::endl
- ;
- }
- }
-
-/***********************************************************************
- * Peek and Poke
- **********************************************************************/
- void poke32(wb_addr_type addr, boost::uint32_t data){
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_POKE32>(addr, data);
- }
-
- boost::uint32_t peek32(wb_addr_type addr){
- return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr);
- }
-
- void poke16(wb_addr_type addr, boost::uint16_t data){
- this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_POKE16>(addr, data);
- }
-
- boost::uint16_t peek16(wb_addr_type addr){
- return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr);
- }
-
- template <class T, usrp2_reg_action_t action>
- T get_reg(wb_addr_type addr, T data = 0){
- //setup the out data
- usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.reg_args.addr = htonl(addr);
- out_data.data.reg_args.data = htonl(boost::uint32_t(data));
- out_data.data.reg_args.action = action;
-
- //send and recv
- usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_REG);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE);
- return T(ntohl(in_data.data.reg_args.data));
- }
-
-/***********************************************************************
- * 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 = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
- out_data.data.spi_args.dev = htonl(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, MIN_PROTO_COMPAT_SPI);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
-
- return ntohl(in_data.data.spi_args.data);
- }
-
-/***********************************************************************
- * I2C
- **********************************************************************/
- void write_i2c(boost::uint8_t addr, const byte_vector_t &buf){
- //setup the out data
- usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO);
- out_data.data.i2c_args.addr = addr;
- out_data.data.i2c_args.bytes = buf.size();
-
- //limitation of i2c transaction size
- UHD_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 = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
- }
-
- byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
- //setup the out data
- usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO);
- out_data.data.i2c_args.addr = addr;
- out_data.data.i2c_args.bytes = num_bytes;
-
- //limitation of i2c transaction size
- UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data));
-
- //send and recv
- usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
- UHD_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;
- }
-
-/***********************************************************************
- * UART
- **********************************************************************/
- void write_uart(boost::uint8_t dev, const std::string &buf){
- //first tokenize the string into 20-byte substrings
- boost::offset_separator f(20, 20, true, true);
- boost::tokenizer<boost::offset_separator> tok(buf, f);
- std::vector<std::string> queue(tok.begin(), tok.end());
-
- BOOST_FOREACH(std::string item, queue) {
- //setup the out data
- usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO);
- out_data.data.uart_args.dev = dev;
- out_data.data.uart_args.bytes = item.size();
-
- //limitation of uart transaction size
- UHD_ASSERT_THROW(item.size() <= sizeof(out_data.data.uart_args.data));
-
- //copy in the data
- std::copy(item.begin(), item.end(), out_data.data.uart_args.data);
-
- //send and recv
- usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE);
- }
- }
-
- std::string read_uart(boost::uint8_t dev){
- int readlen = 20;
- std::string result;
- while(readlen == 20) { //while we keep receiving full packets
- //setup the out data
- usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
- out_data.id = htonl(USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO);
- out_data.data.uart_args.dev = dev;
- out_data.data.uart_args.bytes = 20;
-
- //limitation of uart transaction size
- //UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.uart_args.data));
-
- //send and recv
- usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE);
- readlen = in_data.data.uart_args.bytes;
-
- //copy out the data
- result += std::string((const char *)in_data.data.uart_args.data, (size_t)readlen);
- }
- return result;
- }
-
- gps_send_fn_t get_gps_write_fn(void) {
- return boost::bind(&usrp2_iface_impl::write_uart, this, 2, _1); //2 is the GPS UART port on USRP2
- }
-
- gps_recv_fn_t get_gps_read_fn(void) {
- return boost::bind(&usrp2_iface_impl::read_uart, this, 2); //2 is the GPS UART port on USRP2
- }
-
-/***********************************************************************
- * Send/Recv over control
- **********************************************************************/
- usrp2_ctrl_data_t ctrl_send_and_recv(
- const usrp2_ctrl_data_t &out_data,
- boost::uint32_t lo = USRP2_FW_COMPAT_NUM,
- boost::uint32_t hi = USRP2_FW_COMPAT_NUM
- ){
- boost::mutex::scoped_lock lock(_ctrl_mutex);
-
- //fill in the seq number and send
- usrp2_ctrl_data_t out_copy = out_data;
- out_copy.proto_ver = htonl(_protocol_compat);
- 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
- boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
- const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
- while(true){
- size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CTRL_RECV_TIMEOUT);
- boost::uint32_t compat = ntohl(ctrl_data_in->proto_ver);
- if(len >= sizeof(boost::uint32_t) and (hi < compat or lo > compat)){
- throw uhd::runtime_error(str(boost::format(
- "\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));
- }
- if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){
- return *ctrl_data_in;
- }
- if (len == 0) break; //timeout
- //didnt get seq or bad packet, continue looking...
- }
- throw uhd::runtime_error("no control response");
- }
-
- rev_type get_rev(void){
- switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["rev"])){
- case 0x0300:
- case 0x0301: return USRP2_REV3;
- case 0x0400: return USRP2_REV4;
- case 0x0A00: return USRP_N200;
- case 0x0A01: return USRP_N210;
- case 0x0A10: return USRP_N200_R4;
- case 0x0A11: return USRP_N210_R4;
- }
- return USRP_NXXX; //unknown type
- }
-
- 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???";
- }
- UHD_THROW_INVALID_CODE_PATH();
- }
-
-private:
- //this lovely lady makes it all possible
- udp_simple::sptr _ctrl_transport;
-
- //used in send/recv
- boost::mutex _ctrl_mutex;
- boost::uint32_t _ctrl_seq_num;
- boost::uint32_t _protocol_compat;
-
- //lock thread stuff
- boost::thread_group _lock_thread_group;
-};
-
-/***********************************************************************
- * Public make function for usrp2 interface
- **********************************************************************/
-usrp2_iface::sptr usrp2_iface::make(udp_simple::sptr ctrl_transport){
- return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport));
-}
-
diff --git a/host/lib/usrp2/usrp2_iface.hpp b/host/lib/usrp2/usrp2_iface.hpp
deleted file mode 100644
index f36febce4..000000000
--- a/host/lib/usrp2/usrp2_iface.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/types/serial.hpp>
-#include <uhd/usrp/mboard_eeprom.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <boost/function.hpp>
-#include "usrp2_regs.hpp"
-#include "wb_iface.hpp"
-#include <string>
-
-//TODO: kill this crap when you have the top level GPS include file
-typedef boost::function<void(std::string)> gps_send_fn_t;
-typedef boost::function<std::string(void)> gps_recv_fn_t;
-
-/*!
- * The usrp2 interface class:
- * Provides a set of functions to implementation layer.
- * Including spi, peek, poke, control...
- */
-class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{
-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);
-
- virtual gps_recv_fn_t get_gps_read_fn(void) = 0;
- virtual gps_send_fn_t get_gps_write_fn(void) = 0;
-
- //! The list of possible revision types
- enum rev_type {
- USRP2_REV3 = 3,
- USRP2_REV4 = 4,
- USRP_N200 = 200,
- USRP_N200_R4 = 201,
- USRP_N210 = 210,
- USRP_N210_R4 = 211,
- USRP_NXXX = 0
- };
-
- //! Get the revision type for this device
- virtual rev_type get_rev(void) = 0;
-
- //! Get the canonical name for this device
- virtual const std::string get_cname(void) = 0;
-
- //! Lock the device to this iface
- virtual void lock_device(bool lock) = 0;
-
- //! Is this device locked?
- virtual bool is_device_locked(void) = 0;
-
- //motherboard eeprom map structure
- uhd::usrp::mboard_eeprom_t mb_eeprom;
-};
-
-#endif /* INCLUDED_USRP2_IFACE_HPP */
diff --git a/host/lib/usrp2/usrp2_impl.cpp b/host/lib/usrp2/usrp2_impl.cpp
deleted file mode 100644
index e00924ebd..000000000
--- a/host/lib/usrp2/usrp2_impl.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "fw_common.h"
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/transport/if_addrs.hpp>
-#include <uhd/transport/udp_zero_copy.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/static.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <boost/format.hpp>
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/bind.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/asio/ip/address_v4.hpp>
-#include <boost/asio.hpp> //used for htonl and ntohl
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-namespace asio = boost::asio;
-
-/***********************************************************************
- * Discovery over the udp transport
- **********************************************************************/
-static device_addrs_t usrp2_find(const device_addr_t &hint_){
- //handle the multi-device discovery
- device_addrs_t hints = separate_device_addr(hint_);
- if (hints.size() > 1){
- device_addrs_t found_devices;
- BOOST_FOREACH(const device_addr_t &hint_i, hints){
- device_addrs_t found_devices_i = usrp2_find(hint_i);
- if (found_devices_i.size() != 1) throw uhd::value_error(str(boost::format(
- "Could not resolve device hint \"%s\" to a single device."
- ) % hint_i.to_string()));
- found_devices.push_back(found_devices_i[0]);
- }
- return device_addrs_t(1, combine_device_addrs(found_devices));
- }
-
- //initialize the hint for a single device case
- UHD_ASSERT_THROW(hints.size() <= 1);
- hints.resize(1); //in case it was empty
- device_addr_t hint = hints[0];
- device_addrs_t usrp2_addrs;
-
- //return an empty list of addresses when type is set to non-usrp2
- if (hint.has_key("type") and hint["type"] != "usrp2") return usrp2_addrs;
-
- //if no address was specified, send a broadcast on each interface
- if (not hint.has_key("addr")){
- BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
- //avoid the loopback device
- if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue;
-
- //create a new hint with this broadcast address
- device_addr_t new_hint = hint;
- new_hint["addr"] = if_addrs.bcast;
-
- //call discover with the new hint and append results
- device_addrs_t new_usrp2_addrs = usrp2_find(new_hint);
- usrp2_addrs.insert(usrp2_addrs.begin(),
- new_usrp2_addrs.begin(), new_usrp2_addrs.end()
- );
- }
- return usrp2_addrs;
- }
-
- //create a udp transport to communicate
- 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
- );
-
- //send a hello control packet
- usrp2_ctrl_data_t ctrl_data_out = usrp2_ctrl_data_t();
- ctrl_data_out.proto_ver = uhd::htonx<boost::uint32_t>(USRP2_FW_COMPAT_NUM);
- ctrl_data_out.id = uhd::htonx<boost::uint32_t>(USRP2_CTRL_ID_WAZZUP_BRO);
- udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
-
- //loop and recieve until the timeout
- boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
- const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
- while(true){
- size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));
- if (len > offsetof(usrp2_ctrl_data_t, data) and ntohl(ctrl_data_in->id) == USRP2_CTRL_ID_WAZZUP_DUDE){
-
- //make a boost asio ipv4 with the raw addr in host byte order
- boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr));
- device_addr_t new_addr;
- new_addr["type"] = "usrp2";
- new_addr["addr"] = ip_addr.to_string();
-
- //Attempt to read the name from the EEPROM and perform filtering.
- //This operation can throw due to compatibility mismatch.
- try{
- usrp2_iface::sptr iface = usrp2_iface::make(udp_simple::make_connected(
- new_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
- ));
- if (iface->is_device_locked()) continue; //ignore locked devices
- mboard_eeprom_t mb_eeprom = iface->mb_eeprom;
- new_addr["name"] = mb_eeprom["name"];
- new_addr["serial"] = mb_eeprom["serial"];
- }
- catch(const std::exception &){
- //set these values as empty string so the device may still be found
- //and the filter's below can still operate on the discovered device
- new_addr["name"] = "";
- new_addr["serial"] = "";
- }
-
- //filter the discovered device below by matching optional keys
- if (
- (not hint.has_key("name") or hint["name"] == new_addr["name"]) and
- (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])
- ){
- usrp2_addrs.push_back(new_addr);
- }
-
- //dont break here, it will exit the while loop
- //just continue on to the next loop iteration
- }
- if (len == 0) break; //timeout
- }
-
- return usrp2_addrs;
-}
-
-/***********************************************************************
- * Make
- **********************************************************************/
-static device::sptr usrp2_make(const device_addr_t &device_addr){
- return device::sptr(new usrp2_impl(device_addr));
-}
-
-UHD_STATIC_BLOCK(register_usrp2_device){
- device::register_device(&usrp2_find, &usrp2_make);
-}
-
-/***********************************************************************
- * MTU Discovery
- **********************************************************************/
-struct mtu_result_t{
- size_t recv_mtu, send_mtu;
-};
-
-static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &user_mtu){
- udp_simple::sptr udp_sock = udp_simple::make_connected(
- addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
- );
-
- //The FPGA offers 4K buffers, and the user may manually request this.
- //However, multiple simultaneous receives (2DSP slave + 2DSP master),
- //require that buffering to be used internally, and this is a safe setting.
- std::vector<boost::uint8_t> buffer(std::max(user_mtu.recv_mtu, user_mtu.send_mtu));
- usrp2_ctrl_data_t *ctrl_data = reinterpret_cast<usrp2_ctrl_data_t *>(&buffer.front());
- static const double echo_timeout = 0.020; //20 ms
-
- //test holler - check if its supported in this fw version
- ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO);
- ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM);
- ctrl_data->data.echo_args.len = htonl(sizeof(usrp2_ctrl_data_t));
- udp_sock->send(boost::asio::buffer(buffer, sizeof(usrp2_ctrl_data_t)));
- udp_sock->recv(boost::asio::buffer(buffer), echo_timeout);
- if (ntohl(ctrl_data->id) != USRP2_CTRL_ID_HOLLER_BACK_DUDE)
- throw uhd::not_implemented_error("holler protocol not implemented");
-
- size_t min_recv_mtu = sizeof(usrp2_ctrl_data_t), max_recv_mtu = user_mtu.recv_mtu;
- size_t min_send_mtu = sizeof(usrp2_ctrl_data_t), max_send_mtu = user_mtu.send_mtu;
-
- while (min_recv_mtu < max_recv_mtu){
-
- size_t test_mtu = (max_recv_mtu/2 + min_recv_mtu/2 + 3) & ~3;
-
- ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO);
- ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM);
- ctrl_data->data.echo_args.len = htonl(test_mtu);
- udp_sock->send(boost::asio::buffer(buffer, sizeof(usrp2_ctrl_data_t)));
-
- size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout);
-
- if (len >= test_mtu) min_recv_mtu = test_mtu;
- else max_recv_mtu = test_mtu - 4;
-
- }
-
- while (min_send_mtu < max_send_mtu){
-
- size_t test_mtu = (max_send_mtu/2 + min_send_mtu/2 + 3) & ~3;
-
- ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO);
- ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM);
- ctrl_data->data.echo_args.len = htonl(sizeof(usrp2_ctrl_data_t));
- udp_sock->send(boost::asio::buffer(buffer, test_mtu));
-
- size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout);
- if (len >= sizeof(usrp2_ctrl_data_t)) len = ntohl(ctrl_data->data.echo_args.len);
-
- if (len >= test_mtu) min_send_mtu = test_mtu;
- else max_send_mtu = test_mtu - 4;
- }
-
- mtu_result_t mtu;
- mtu.recv_mtu = min_recv_mtu;
- mtu.send_mtu = min_send_mtu;
- return mtu;
-}
-
-/***********************************************************************
- * Helpers
- **********************************************************************/
-static void init_xport(zero_copy_if::sptr xport){
- //Send a small data packet so the usrp2 knows the udp source port.
- //This setup must happen before further initialization occurs
- //or the async update packets will cause ICMP destination unreachable.
- static const boost::uint32_t data[2] = {
- uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
- uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
- };
-
- transport::managed_send_buffer::sptr send_buff = xport->get_send_buff();
- std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
- send_buff->commit(sizeof(data));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
- UHD_MSG(status) << "Opening a USRP2/N-Series device..." << std::endl;
- device_addr_t device_addr = _device_addr;
-
- //setup the dsp transport hints (default to a large recv buff)
- if (not device_addr.has_key("recv_buff_size")){
- #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD)
- //limit buffer resize on macos or it will error
- device_addr["recv_buff_size"] = "1e6";
- #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)
- //set to half-a-second of buffering at max rate
- device_addr["recv_buff_size"] = "50e6";
- #endif
- }
-
- device_addrs_t device_args = separate_device_addr(device_addr);
-
- //extract the user's requested MTU size or default
- mtu_result_t user_mtu;
- user_mtu.recv_mtu = size_t(device_addr.cast<double>("recv_frame_size", udp_simple::mtu));
- user_mtu.send_mtu = size_t(device_addr.cast<double>("send_frame_size", udp_simple::mtu));
-
- try{
- //calculate the minimum send and recv mtu of all devices
- mtu_result_t mtu = determine_mtu(device_args[0]["addr"], user_mtu);
- for (size_t i = 1; i < device_args.size(); i++){
- mtu_result_t mtu_i = determine_mtu(device_args[i]["addr"], user_mtu);
- mtu.recv_mtu = std::min(mtu.recv_mtu, mtu_i.recv_mtu);
- mtu.send_mtu = std::min(mtu.send_mtu, mtu_i.send_mtu);
- }
-
- device_addr["recv_frame_size"] = boost::lexical_cast<std::string>(mtu.recv_mtu);
- device_addr["send_frame_size"] = boost::lexical_cast<std::string>(mtu.send_mtu);
-
- UHD_MSG(status) << boost::format("Current recv frame size: %d bytes") % mtu.recv_mtu << std::endl;
- UHD_MSG(status) << boost::format("Current send frame size: %d bytes") % mtu.send_mtu << std::endl;
- }
- catch(const uhd::not_implemented_error &){
- //just ignore this error, makes older fw work...
- }
-
- device_args = separate_device_addr(device_addr); //update args for new frame sizes
-
- ////////////////////////////////////////////////////////////////////
- // create controller objects and initialize the properties tree
- ////////////////////////////////////////////////////////////////////
- _tree = property_tree::make();
- _tree->create<std::string>("/name").set("USRP2 / N-Series Device");
-
- for (size_t mbi = 0; mbi < device_args.size(); mbi++){
- const device_addr_t device_args_i = device_args[mbi];
- const std::string mb = boost::lexical_cast<std::string>(mbi);
- const std::string addr = device_args_i["addr"];
- property_tree::path_type mb_path = "/mboards/" + mb;
-
- ////////////////////////////////////////////////////////////////
- // construct transports for dsp and async errors
- ////////////////////////////////////////////////////////////////
- UHD_LOG << "Making transport for DSP0..." << std::endl;
- _mbc[mb].dsp_xports.push_back(udp_zero_copy::make(
- addr, BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_args_i
- ));
- init_xport(_mbc[mb].dsp_xports.back());
-
- UHD_LOG << "Making transport for DSP1..." << std::endl;
- _mbc[mb].dsp_xports.push_back(udp_zero_copy::make(
- addr, BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_args_i
- ));
- init_xport(_mbc[mb].dsp_xports.back());
-
- UHD_LOG << "Making transport for ERR0..." << std::endl;
- _mbc[mb].err_xports.push_back(udp_zero_copy::make(
- addr, BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t()
- ));
- init_xport(_mbc[mb].err_xports.back());
-
- ////////////////////////////////////////////////////////////////
- // create the iface that controls i2c, spi, uart, and wb
- ////////////////////////////////////////////////////////////////
- _mbc[mb].iface = usrp2_iface::make(udp_simple::make_connected(
- addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
- ));
- _tree->create<std::string>(mb_path / "name").set(_mbc[mb].iface->get_cname());
-
- ////////////////////////////////////////////////////////////////
- // setup the mboard eeprom
- ////////////////////////////////////////////////////////////////
- _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
- .set(_mbc[mb].iface->mb_eeprom)
- .subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1));
-
- ////////////////////////////////////////////////////////////////
- // create clock control objects
- ////////////////////////////////////////////////////////////////
- _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface);
- _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));
-
- ////////////////////////////////////////////////////////////////
- // create codec control objects
- ////////////////////////////////////////////////////////////////
- property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A";
- property_tree::path_type 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);
- 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<std::string>(rx_codec_path / "name").set("ads62p44");
- _tree->create<meta_range_t>(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5));
- _tree->create<double>(rx_codec_path / "gains/digital/value")
- .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0);
- _tree->create<meta_range_t>(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05));
- _tree->create<double>(rx_codec_path / "gains/fine/value")
- .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mbc[mb].codec, _1)).set(0);
- }break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- _tree->create<std::string>(rx_codec_path / "name").set("ltc2284");
- break;
-
- case usrp2_iface::USRP_NXXX:
- _tree->create<std::string>(rx_codec_path / "name").set("??????");
- break;
- }
- _tree->create<std::string>(tx_codec_path / "name").set("ad9777");
-
- ////////////////////////////////////////////////////////////////
- // create gpsdo control objects
- ////////////////////////////////////////////////////////////////
- if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){
- _mbc[mb].gps = gps_ctrl::make(
- _mbc[mb].iface->get_gps_write_fn(),
- _mbc[mb].iface->get_gps_read_fn()
- );
- BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){
- _tree->create<sensor_value_t>(mb_path / "sensors" / name)
- .publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name));
- }
- }
-
- ////////////////////////////////////////////////////////////////
- // and do the misc mboard sensors
- ////////////////////////////////////////////////////////////////
- _tree->create<sensor_value_t>(mb_path / "sensors/mimo_locked")
- .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb));
- _tree->create<sensor_value_t>(mb_path / "sensors/ref_locked")
- .publish(boost::bind(&usrp2_impl::get_ref_locked, this, mb));
-
- ////////////////////////////////////////////////////////////////
- // 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].tx_fe = tx_frontend_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT)
- );
- //TODO lots of properties to expose here for frontends
- _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
- .subscribe(boost::bind(&usrp2_impl::update_rx_subdev_spec, this, mb, _1));
- _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
- .subscribe(boost::bind(&usrp2_impl::update_tx_subdev_spec, this, mb, _1));
-
- ////////////////////////////////////////////////////////////////
- // 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].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
- ));
- for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){
- _tree->access<double>(mb_path / "tick_rate")
- .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _mbc[mb].rx_dsps[dspno], _1));
- //This is a hack/fix for the lingering packet problem.
- //The dsp core starts streaming briefly... now we flush
- _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for lingering
- _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for expected
- property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
- _tree->create<double>(rx_dsp_path / "rate/value")
- .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _mbc[mb].rx_dsps[dspno], _1))
- .subscribe(boost::bind(&usrp2_impl::update_rx_samp_rate, this, _1));
- _tree->create<double>(rx_dsp_path / "freq/value")
- .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1));
- _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
- .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno]));
- _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd")
- .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _mbc[mb].rx_dsps[dspno], _1));
- }
-
- ////////////////////////////////////////////////////////////////
- // 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
- );
- _tree->access<double>(mb_path / "tick_rate")
- .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1));
- _tree->create<double>(mb_path / "tx_dsps/0/rate/value")
- .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1))
- .subscribe(boost::bind(&usrp2_impl::update_tx_samp_rate, this, _1));
- _tree->create<double>(mb_path / "tx_dsps/0/freq/value")
- .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1));
- _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
- .publish(boost::bind(&usrp2_impl::get_tx_dsp_freq_range, this, mb));
-
- //setup dsp flow control
- const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20);
- const size_t send_frame_size = _mbc[mb].dsp_xports.front()->get_send_frame_size();
- const double ups_per_fifo = device_args_i.cast<double>("ups_per_fifo", 8.0);
- _mbc[mb].tx_dsp->set_updates(
- (ups_per_sec > 0.0)? size_t(100e6/*approx tick rate*//ups_per_sec) : 0,
- (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0
- );
-
- ////////////////////////////////////////////////////////////////
- // create time control objects
- ////////////////////////////////////////////////////////////////
- time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_imm = U2_REG_TIME64_SECS_RB_IMM;
- time64_rb_bases.rb_ticks_imm = U2_REG_TIME64_TICKS_RB_IMM;
- time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS;
- time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_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
- );
- _tree->access<double>(mb_path / "tick_rate")
- .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1));
- _tree->create<time_spec_t>(mb_path / "time/now")
- .publish(boost::bind(&time64_core_200::get_time_now, _mbc[mb].time64))
- .subscribe(boost::bind(&time64_core_200::set_time_now, _mbc[mb].time64, _1));
- _tree->create<time_spec_t>(mb_path / "time/pps")
- .publish(boost::bind(&time64_core_200::get_time_last_pps, _mbc[mb].time64))
- .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1));
- //setup time source props
- _tree->create<std::string>(mb_path / "time_source/value")
- .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1));
- _tree->create<std::vector<std::string> >(mb_path / "time_source/options")
- .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64));
- //setup reference source props
- _tree->create<std::string>(mb_path / "ref_source/value")
- .subscribe(boost::bind(&usrp2_impl::update_ref_source, this, mb, _1));
- static const std::vector<std::string> ref_sources = boost::assign::list_of("internal")("sma")("mimo");
- _tree->create<std::vector<std::string> >(mb_path / "ref_source/options").set(ref_sources);
-
- ////////////////////////////////////////////////////////////////
- // create dboard control objects
- ////////////////////////////////////////////////////////////////
-
- //read the dboard eeprom to extract the dboard ids
- dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
- rx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
- tx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
- gdb_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
-
- //create the properties and register subscribers
- _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom")
- .set(rx_db_eeprom)
- .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1));
- _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom")
- .set(tx_db_eeprom)
- .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1));
- _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom")
- .set(gdb_eeprom)
- .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);
- _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,
- ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
- _mbc[mb].dboard_iface
- );
- BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_rx_subdev_names()){
- dboard_manager::populate_prop_tree_from_subdev(
- _tree, mb_path / "dboards/A/rx_frontends" / name,
- _mbc[mb].dboard_manager->get_rx_subdev(name)
- );
- }
- BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_tx_subdev_names()){
- dboard_manager::populate_prop_tree_from_subdev(
- _tree, mb_path / "dboards/A/tx_frontends" / name,
- _mbc[mb].dboard_manager->get_tx_subdev(name)
- );
- }
- }
-
- //initialize io handling
- this->io_init();
-
- //do some post-init tasks
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- property_tree::path_type root = "/mboards/" + mb;
- _tree->access<double>(root / "tick_rate").update();
-
- //and now that the tick rate is set, init the host rates to something
- BOOST_FOREACH(const std::string &name, _tree->list(root / "rx_dsps")){
- _tree->access<double>(root / "rx_dsps" / name / "rate" / "value").set(1e6);
- }
- BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){
- _tree->access<double>(root / "tx_dsps" / name / "rate" / "value").set(1e6);
- }
-
- _tree->access<subdev_spec_t>(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0]));
- _tree->access<subdev_spec_t>(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0]));
- _tree->access<std::string>(root / "ref_source/value").set("internal");
- _tree->access<std::string>(root / "time_source/value").set("none");
-
- //GPS installed: use external ref, time, and init time spec
- if (_mbc[mb].gps.get() != NULL){
- _tree->access<std::string>(root / "time_source/value").set("sma");
- _tree->access<std::string>(root / "ref_source/value").set("sma");
- _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1)));
- }
- }
-
-}
-
-usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(
- BOOST_FOREACH(const std::string &mb, _mbc.keys()){
- _mbc[mb].tx_dsp->set_updates(0, 0);
- }
-)}
-
-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);
-}
-
-void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
- if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
- if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
- if (type == "gdb") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
-}
-
-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;
- 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;
- return sensor_value_t("Ref", lock, "locked", "unlocked");
-}
-
-#include <boost/math/special_functions/round.hpp>
-#include <boost/math/special_functions/sign.hpp>
-
-double usrp2_impl::set_tx_dsp_freq(const std::string &mb, const double freq_){
- double new_freq = freq_;
- const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
-
- //calculate the DAC shift (multiples of rate)
- const int sign = boost::math::sign(new_freq);
- const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2);
- const double dac_shift = sign*zone*tick_rate;
- new_freq -= dac_shift; //update FPGA DSP target freq
-
- //set the DAC shift (modulation mode)
- if (zone == 0) _mbc[mb].codec->set_tx_mod_mode(0); //no shift
- else _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
-
- return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq
-}
-
-meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){
- const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
- const meta_range_t dsp_range = _mbc[mb].tx_dsp->get_freq_range();
- return meta_range_t(dsp_range.start() - tick_rate*2, dsp_range.stop() + tick_rate*2, dsp_range.step());
-}
-
-void usrp2_impl::update_ref_source(const std::string &mb, const std::string &source){
- //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);
- else if (source == "sma") _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);
- _mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
- break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);
- else if (source == "sma") _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);
- _mbc[mb].clock->enable_external_ref(source != "internal");
- break;
-
- case usrp2_iface::USRP_NXXX: break;
- }
-
- //always drive the clock over serdes if not locking to it
- _mbc[mb].clock->enable_mimo_clock_out(source != "mimo");
-
- //set the mimo clock delay over the serdes
- if (source != "mimo"){
- 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].clock->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
- break;
-
- case usrp2_iface::USRP2_REV4:
- _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
- break;
-
- default: break; //not handled
- }
- }
-}
diff --git a/host/lib/usrp2/usrp2_impl.hpp b/host/lib/usrp2/usrp2_impl.hpp
deleted file mode 100644
index ad203079b..000000000
--- a/host/lib/usrp2/usrp2_impl.hpp
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_IMPL_HPP
-#define INCLUDED_USRP2_IMPL_HPP
-
-#include "usrp2_iface.hpp"
-#include "clock_ctrl.hpp"
-#include "codec_ctrl.hpp"
-#include "rx_frontend_core_200.hpp"
-#include "tx_frontend_core_200.hpp"
-#include "rx_dsp_core_200.hpp"
-#include "tx_dsp_core_200.hpp"
-#include "time64_core_200.hpp"
-#include <uhd/property_tree.hpp>
-#include <uhd/usrp/gps_ctrl.hpp>
-#include <uhd/device.hpp>
-#include <uhd/utils/pimpl.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 <uhd/usrp/dboard_eeprom.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
-#include <uhd/transport/vrt_if_packet.hpp>
-#include <uhd/transport/udp_simple.hpp>
-#include <uhd/transport/udp_zero_copy.hpp>
-#include <uhd/usrp/dboard_manager.hpp>
-#include <uhd/usrp/subdev_spec.hpp>
-
-static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
-static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
-static const size_t mimo_clock_sync_delay_cycles = 137;
-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;
-
-/*!
- * 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
- */
-uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
- usrp2_iface::sptr iface,
- usrp2_clock_ctrl::sptr clk_ctrl
-);
-
-/*!
- * USRP2 implementation guts:
- * The implementation details are encapsulated here.
- * Handles device properties and streaming...
- */
-class usrp2_impl : public uhd::device{
-public:
- usrp2_impl(const uhd::device_addr_t &);
- ~usrp2_impl(void);
-
- //the io interface
- size_t send(
- const send_buffs_type &, size_t,
- const uhd::tx_metadata_t &, const uhd::io_type_t &,
- uhd::device::send_mode_t, double
- );
- size_t recv(
- const recv_buffs_type &, size_t,
- uhd::rx_metadata_t &, const uhd::io_type_t &,
- uhd::device::recv_mode_t, double
- );
- size_t get_max_send_samps_per_packet(void) const;
- size_t get_max_recv_samps_per_packet(void) const;
- bool recv_async_msg(uhd::async_metadata_t &, double);
-
-private:
- uhd::property_tree::sptr _tree;
- struct mb_container_type{
- usrp2_iface::sptr iface;
- usrp2_clock_ctrl::sptr clock;
- usrp2_codec_ctrl::sptr codec;
- gps_ctrl::sptr gps;
- rx_frontend_core_200::sptr rx_fe;
- tx_frontend_core_200::sptr tx_fe;
- std::vector<rx_dsp_core_200::sptr> rx_dsps;
- tx_dsp_core_200::sptr tx_dsp;
- time64_core_200::sptr time64;
- std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports;
- std::vector<uhd::transport::zero_copy_if::sptr> err_xports;
- uhd::usrp::dboard_manager::sptr dboard_manager;
- uhd::usrp::dboard_iface::sptr dboard_iface;
- size_t rx_chan_occ, tx_chan_occ;
- };
- uhd::dict<std::string, mb_container_type> _mbc;
-
- void set_mb_eeprom(const std::string &, const uhd::usrp::mboard_eeprom_t &);
- void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &);
-
- uhd::sensor_value_t get_mimo_locked(const std::string &);
- uhd::sensor_value_t get_ref_locked(const std::string &);
-
- //device properties interface
- void get(const wax::obj &, wax::obj &val){
- val = _tree; //entry point into property tree
- }
-
- //io impl methods and members
- uhd::otw_type_t _rx_otw_type, _tx_otw_type;
- UHD_PIMPL_DECL(io_impl) _io_impl;
- void io_init(void);
- void update_tick_rate(const double rate);
- void update_rx_samp_rate(const double rate);
- void update_tx_samp_rate(const double rate);
- void update_rx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
- void update_tx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
- double set_tx_dsp_freq(const std::string &, const double);
- uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);
- void update_ref_source(const std::string &, const std::string &);
-};
-
-#endif /* INCLUDED_USRP2_IMPL_HPP */
diff --git a/host/lib/usrp2/usrp2_regs.hpp b/host/lib/usrp2/usrp2_regs.hpp
deleted file mode 100644
index 19c1b45f1..000000000
--- a/host/lib/usrp2/usrp2_regs.hpp
+++ /dev/null
@@ -1,221 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_REGS_HPP
-#define INCLUDED_USRP2_REGS_HPP
-
-////////////////////////////////////////////////////////////////////////
-// Define slave bases
-////////////////////////////////////////////////////////////////////////
-#define ROUTER_RAM_BASE 0x4000
-#define SPI_BASE 0x5000
-#define I2C_BASE 0x5400
-#define GPIO_BASE 0x5800
-#define READBACK_BASE 0x5C00
-#define ETH_BASE 0x6000
-#define SETTING_REGS_BASE 0x7000
-#define PIC_BASE 0x8000
-#define UART_BASE 0x8800
-#define ATR_BASE 0x8C00
-
-////////////////////////////////////////////////////////////////////////
-// Setting register offsets
-////////////////////////////////////////////////////////////////////////
-#define SR_MISC 0 // 7 regs
-#define SR_SIMTIMER 8 // 2
-#define SR_TIME64 10 // 6
-#define SR_BUF_POOL 16 // 4
-
-#define SR_RX_FRONT 24 // 5
-#define SR_RX_CTRL0 32 // 9
-#define SR_RX_DSP0 48 // 7
-#define SR_RX_CTRL1 80 // 9
-#define SR_RX_DSP1 96 // 7
-
-#define SR_TX_FRONT 128 // ?
-#define SR_TX_CTRL 144 // 6
-#define SR_TX_DSP 160 // 5
-
-#define SR_UDP_SM 192 // 64
-
-#define U2_REG_SR_ADDR(sr) (SETTING_REGS_BASE + (4 * (sr)))
-
-/////////////////////////////////////////////////
-// SPI Slave Constants
-////////////////////////////////////////////////
-// Masks for controlling different peripherals
-#define SPI_SS_AD9510 1
-#define SPI_SS_AD9777 2
-#define SPI_SS_RX_DAC 4
-#define SPI_SS_RX_ADC 8
-#define SPI_SS_RX_DB 16
-#define SPI_SS_TX_DAC 32
-#define SPI_SS_TX_ADC 64
-#define SPI_SS_TX_DB 128
-#define SPI_SS_ADS62P44 256 //for usrp2p
-
-/////////////////////////////////////////////////
-// Misc Control
-////////////////////////////////////////////////
-#define U2_REG_MISC_CTRL_CLOCK U2_REG_SR_ADDR(0)
-#define U2_REG_MISC_CTRL_SERDES U2_REG_SR_ADDR(1)
-#define U2_REG_MISC_CTRL_ADC U2_REG_SR_ADDR(2)
-#define U2_REG_MISC_CTRL_LEDS U2_REG_SR_ADDR(3)
-#define U2_REG_MISC_CTRL_PHY U2_REG_SR_ADDR(4)
-#define U2_REG_MISC_CTRL_DBG_MUX U2_REG_SR_ADDR(5)
-#define U2_REG_MISC_CTRL_RAM_PAGE U2_REG_SR_ADDR(6)
-#define U2_REG_MISC_CTRL_FLUSH_ICACHE U2_REG_SR_ADDR(7)
-#define U2_REG_MISC_CTRL_LED_SRC U2_REG_SR_ADDR(8)
-
-#define U2_FLAG_MISC_CTRL_SERDES_ENABLE 8
-#define U2_FLAG_MISC_CTRL_SERDES_PRBSEN 4
-#define U2_FLAG_MISC_CTRL_SERDES_LOOPEN 2
-#define U2_FLAG_MISC_CTRL_SERDES_RXEN 1
-
-#define U2_FLAG_MISC_CTRL_ADC_ON 0x0F
-#define U2_FLAG_MISC_CTRL_ADC_OFF 0x00
-
-/////////////////////////////////////////////////
-// VITA49 64 bit time (write only)
-////////////////////////////////////////////////
-#define U2_REG_TIME64_SECS U2_REG_SR_ADDR(SR_TIME64 + 0)
-#define U2_REG_TIME64_TICKS U2_REG_SR_ADDR(SR_TIME64 + 1)
-#define U2_REG_TIME64_FLAGS U2_REG_SR_ADDR(SR_TIME64 + 2)
-#define U2_REG_TIME64_IMM U2_REG_SR_ADDR(SR_TIME64 + 3)
-#define U2_REG_TIME64_TPS U2_REG_SR_ADDR(SR_TIME64 + 4)
-#define U2_REG_TIME64_MIMO_SYNC U2_REG_SR_ADDR(SR_TIME64 + 5)
-
-//pps flags (see above)
-#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
-#define U2_FLAG_TIME64_PPS_POSEDGE (1 << 0)
-#define U2_FLAG_TIME64_PPS_SMA (0 << 1)
-#define U2_FLAG_TIME64_PPS_MIMO (1 << 1)
-
-#define U2_FLAG_TIME64_LATCH_NOW 1
-#define U2_FLAG_TIME64_LATCH_NEXT_PPS 0
-
-/////////////////////////////////////////////////
-// Readback regs
-////////////////////////////////////////////////
-#define U2_REG_STATUS READBACK_BASE + 4*8
-#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10
-#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11
-#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12
-#define U2_REG_IRQ_RB READBACK_BASE + 4*13
-#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14
-#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15
-
-/////////////////////////////////////////////////
-// RX FE
-////////////////////////////////////////////////
-#define U2_REG_RX_FE_SWAP_IQ U2_REG_SR_ADDR(SR_RX_FRONT + 0) //lower bit
-#define U2_REG_RX_FE_MAG_CORRECTION U2_REG_SR_ADDR(SR_RX_FRONT + 1) //18 bits
-#define U2_REG_RX_FE_PHASE_CORRECTION U2_REG_SR_ADDR(SR_RX_FRONT + 2) //18 bits
-#define U2_REG_RX_FE_OFFSET_I U2_REG_SR_ADDR(SR_RX_FRONT + 3) //18 bits
-#define U2_REG_RX_FE_OFFSET_Q U2_REG_SR_ADDR(SR_RX_FRONT + 4) //18 bits
-
-/////////////////////////////////////////////////
-// TX FE
-////////////////////////////////////////////////
-#define U2_REG_TX_FE_DC_OFFSET_I U2_REG_SR_ADDR(SR_TX_FRONT + 0) //24 bits
-#define U2_REG_TX_FE_DC_OFFSET_Q U2_REG_SR_ADDR(SR_TX_FRONT + 1) //24 bits
-#define U2_REG_TX_FE_MAC_CORRECTION U2_REG_SR_ADDR(SR_TX_FRONT + 2) //18 bits
-#define U2_REG_TX_FE_PHASE_CORRECTION U2_REG_SR_ADDR(SR_TX_FRONT + 3) //18 bits
-#define U2_REG_TX_FE_MUX U2_REG_SR_ADDR(SR_TX_FRONT + 4) //8 bits (std output = 0x10, reversed = 0x01)
-
-/////////////////////////////////////////////////
-// DSP TX Regs
-////////////////////////////////////////////////
-#define U2_REG_DSP_TX_FREQ U2_REG_SR_ADDR(SR_TX_DSP + 0)
-#define U2_REG_DSP_TX_SCALE_IQ U2_REG_SR_ADDR(SR_TX_DSP + 1)
-#define U2_REG_DSP_TX_INTERP_RATE U2_REG_SR_ADDR(SR_TX_DSP + 2)
-
-/////////////////////////////////////////////////
-// DSP RX Regs
-////////////////////////////////////////////////
-#define U2_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \
- (U2_REG_SR_ADDR(SR_RX_DSP0 + offset)) : \
- (U2_REG_SR_ADDR(SR_RX_DSP1 + offset)))
-
-#define U2_REG_DSP_RX_FREQ(which) U2_REG_DSP_RX_HELPER(which, 0)
-#define U2_REG_DSP_RX_DECIM(which) U2_REG_DSP_RX_HELPER(which, 2)
-#define U2_REG_DSP_RX_MUX(which) U2_REG_DSP_RX_HELPER(which, 3)
-
-#define U2_FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0)
-#define U2_FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
-
-////////////////////////////////////////////////
-// GPIO
-////////////////////////////////////////////////
-#define U2_REG_GPIO_IO GPIO_BASE + 0
-#define U2_REG_GPIO_DDR GPIO_BASE + 4
-#define U2_REG_GPIO_TX_SEL GPIO_BASE + 8
-#define U2_REG_GPIO_RX_SEL GPIO_BASE + 12
-
-// each 2-bit sel field is layed out this way
-#define U2_FLAG_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register
-#define U2_FLAG_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
-#define U2_FLAG_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric
-#define U2_FLAG_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric
-
-///////////////////////////////////////////////////
-// ATR Controller
-////////////////////////////////////////////////
-#define U2_REG_ATR_IDLE_TXSIDE ATR_BASE + 0
-#define U2_REG_ATR_IDLE_RXSIDE ATR_BASE + 2
-#define U2_REG_ATR_INTX_TXSIDE ATR_BASE + 4
-#define U2_REG_ATR_INTX_RXSIDE ATR_BASE + 6
-#define U2_REG_ATR_INRX_TXSIDE ATR_BASE + 8
-#define U2_REG_ATR_INRX_RXSIDE ATR_BASE + 10
-#define U2_REG_ATR_FULL_TXSIDE ATR_BASE + 12
-#define U2_REG_ATR_FULL_RXSIDE ATR_BASE + 14
-
-///////////////////////////////////////////////////
-// RX CTRL regs
-///////////////////////////////////////////////////
-#define U2_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \
- (U2_REG_SR_ADDR(SR_RX_CTRL0 + offset)) : \
- (U2_REG_SR_ADDR(SR_RX_CTRL1 + offset)))
-
-#define U2_REG_RX_CTRL_STREAM_CMD(which) U2_REG_RX_CTRL_HELPER(which, 0)
-#define U2_REG_RX_CTRL_TIME_SECS(which) U2_REG_RX_CTRL_HELPER(which, 1)
-#define U2_REG_RX_CTRL_TIME_TICKS(which) U2_REG_RX_CTRL_HELPER(which, 2)
-#define U2_REG_RX_CTRL_CLEAR(which) U2_REG_RX_CTRL_HELPER(which, 3)
-#define U2_REG_RX_CTRL_VRT_HDR(which) U2_REG_RX_CTRL_HELPER(which, 4)
-#define U2_REG_RX_CTRL_VRT_SID(which) U2_REG_RX_CTRL_HELPER(which, 5)
-#define U2_REG_RX_CTRL_VRT_TLR(which) U2_REG_RX_CTRL_HELPER(which, 6)
-#define U2_REG_RX_CTRL_NSAMPS_PP(which) U2_REG_RX_CTRL_HELPER(which, 7)
-#define U2_REG_RX_CTRL_NCHANNELS(which) U2_REG_RX_CTRL_HELPER(which, 8)
-
-///////////////////////////////////////////////////
-// TX CTRL regs
-///////////////////////////////////////////////////
-#define U2_REG_TX_CTRL_NUM_CHAN U2_REG_SR_ADDR(SR_TX_CTRL + 0)
-#define U2_REG_TX_CTRL_CLEAR_STATE U2_REG_SR_ADDR(SR_TX_CTRL + 1)
-#define U2_REG_TX_CTRL_REPORT_SID U2_REG_SR_ADDR(SR_TX_CTRL + 2)
-#define U2_REG_TX_CTRL_POLICY U2_REG_SR_ADDR(SR_TX_CTRL + 3)
-#define U2_REG_TX_CTRL_CYCLES_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 4)
-#define U2_REG_TX_CTRL_PACKETS_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 5)
-
-#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
-#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)
-#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2)
-
-//enable flag for registers: cycles and packets per update packet
-#define U2_FLAG_TX_CTRL_UP_ENB (1ul << 31)
-
-#endif /* INCLUDED_USRP2_REGS_HPP */