From 11539ef6f690b4ebd69485be9a61f5422d8cdc99 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Jun 2011 14:00:22 -0700 Subject: usrp2: moved impl back into usrp subdir --- host/lib/usrp/usrp2/CMakeLists.txt | 35 +-- host/lib/usrp/usrp2/codec_impl.cpp | 181 ------------- host/lib/usrp/usrp2/dboard_impl.cpp | 183 ------------- host/lib/usrp/usrp2/dsp_impl.cpp | 256 ------------------ host/lib/usrp/usrp2/io_impl.cpp | 187 +++++++------ host/lib/usrp/usrp2/mboard_impl.cpp | 522 ------------------------------------ host/lib/usrp/usrp2/usrp2_iface.cpp | 10 +- host/lib/usrp/usrp2/usrp2_iface.hpp | 11 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 431 +++++++++++++++++++++++++---- host/lib/usrp/usrp2/usrp2_impl.hpp | 189 ++++--------- 10 files changed, 560 insertions(+), 1445 deletions(-) delete mode 100644 host/lib/usrp/usrp2/codec_impl.cpp delete mode 100644 host/lib/usrp/usrp2/dboard_impl.cpp delete mode 100644 host/lib/usrp/usrp2/dsp_impl.cpp delete mode 100644 host/lib/usrp/usrp2/mboard_impl.cpp (limited to 'host/lib/usrp/usrp2') 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 . -// - -#include "usrp2_impl.hpp" -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; -using namespace boost::assign; - -//this only applies to N2XX -static const uhd::dict 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()){ - 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()) { - case CODEC_PROP_GAIN_I: - case CODEC_PROP_GAIN_Q: - this->rx_codec_set_gain(val.as(), 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()){ - 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 . -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include "fw_common.h" -#include -#include -#include -#include -#include -#include -#include -#include //htonl and ntohl -#include - -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()){ - 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()){ - - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as(); - _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()){ - 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()){ - - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as(); - _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as(); - _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 . -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * DSP impl and methods - **********************************************************************/ -struct usrp2_mboard_impl::dsp_impl{ - uhd::dict ddc_decim; - uhd::dict ddc_freq; - uhd::dict duc_interp; - uhd::dict duc_freq; - std::vector decim_and_interp_rates; - uhd::dict 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 -static rate_type pick_closest_rate(double exact_rate, const std::vector &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()){ - 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()){ - - case DSP_PROP_STREAM_CMD: - issue_ddc_stream_cmd(val.as(), which_dsp); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as(); - _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(); - _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()){ - 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()){ - - case DSP_PROP_FREQ_SHIFT:{ - const double codec_rate = get_master_clock_freq(); - double new_freq = val.as(); - - //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(); - _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 #include #include -#include -#include #include #include #include @@ -134,15 +132,10 @@ private: **********************************************************************/ struct usrp2_impl::io_impl{ - io_impl(std::vector &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()[0] = uhd::htonx(fc_mon.get_curr_seq_out()); @@ -166,15 +158,8 @@ struct usrp2_impl::io_impl{ return buff; } - std::vector &dsp_xports; - - //mappings from channel index to dsp xport - std::vector send_map, recv_map; - - //previous state for each buffer - std::vector prev_infos; - - //flow control monitors + //tx dsp: xports and flow control monitors + std::vector tx_xports; std::vector 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_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(); - 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(); - 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(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().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(); - _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().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(); - _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(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 . -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include "fw_common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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(), &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("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("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()){ - 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 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()){ - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as(); - update_clock_config(); - return; - - case MBOARD_PROP_TIME_NOW: - set_time_spec(val.as(), true); - return; - - case MBOARD_PROP_TIME_PPS: - set_time_spec(val.as(), false); - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC:{ - _rx_subdev_spec = val.as(); - 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()){ - 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()){ - 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(); - 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() - )); - } - _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().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() == 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(addr, data); } - boost::uint32_t peek32(boost::uint32_t addr){ + boost::uint32_t peek32(wb_addr_type addr){ return this->get_reg(addr); } - void poke16(boost::uint32_t addr, boost::uint16_t data){ + void poke16(wb_addr_type addr, boost::uint16_t data){ this->get_reg(addr, data); } - boost::uint16_t peek16(boost::uint32_t addr){ + boost::uint16_t peek16(wb_addr_type addr){ return this->get_reg(addr); } template - 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 -#include +#include +#include #include #include -#include #include -#include -#include #include "usrp2_regs.hpp" - +#include "wb_iface.hpp" +#include //TODO: kill this crap when you have the top level GPS include file typedef boost::function gps_send_fn_t; @@ -38,7 +37,7 @@ typedef boost::function 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 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 #include #include -#include +#include #include #include #include -#include +#include #include #include #include #include +#include #include #include //used for htonl and ntohl -#include using namespace uhd; using namespace uhd::usrp; @@ -226,6 +226,23 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u 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(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); +} + /*********************************************************************** * Structors **********************************************************************/ @@ -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("/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(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(mb_path / "name").set(_mbc[mb].iface->get_cname()); + + //////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////// + _tree->create(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(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(rx_codec_path / "gains"); //phony property so this dir exists + _tree->create(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(rx_codec_path / "name").set("ads62p44"); + _tree->create(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5)); + _tree->create(rx_codec_path / "gains/digital/value") + .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0); + _tree->create(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05)); + _tree->create(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(rx_codec_path / "name").set("ltc2284"); + break; + + case usrp2_iface::USRP_NXXX: + _tree->create(rx_codec_path / "name").set("??????"); + break; + } + _tree->create(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(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(mb_path / "sensors/mimo_locked") + .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb)); + _tree->create(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(mb_path / "rx_subdev_spec") + .subscribe(boost::bind(&usrp2_impl::update_rx_subdev_spec, this, mb, _1)); + _tree->create(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(i) : ""; - _mboard_dict[name] = _mboards.back(); + for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){ + _tree->access(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(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(rx_dsp_path / "freq/value") + .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1)); + _tree->create(rx_dsp_path / "freq/range") + .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno])); + _tree->create(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(mb_path / "tick_rate") + .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1)); + _tree->create(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(mb_path / "tx_dsps/0/freq/value") + .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1)); + _tree->create(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("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("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(mb_path / "tick_rate") + .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1)); + _tree->create(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(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(mb_path / "time_source/value") + .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1)); + _tree->create >(mb_path / "time_source/options") + .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64)); + //setup reference source props + _tree->create(mb_path / "ref_source/value") + .subscribe(boost::bind(&usrp2_impl::update_ref_source, this, mb, _1)); + static const std::vector ref_sources = boost::assign::list_of("internal")("sma")("mimo"); + _tree->create >(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(mb_path / "dboards/A/rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1)); + _tree->create(mb_path / "dboards/A/tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1)); + _tree->create(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(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(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(root / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){ + _tree->access(root / "tx_dsps" / name / "rate" / "value").set(1e6); + } + + _tree->access(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0])); + _tree->access(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0])); + _tree->access(root / "ref_source/value").set("internal"); + _tree->access(root / "time_source/value").set("none"); + + //GPS installed: use external ref, time, and init time spec + if (_mbc[mb].gps.get() != NULL){ + _tree->access(root / "time_source/value").set("sma"); + _tree->access(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()){ - 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 +#include - 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("/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("/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 #include #include #include @@ -37,6 +43,13 @@ #include #include +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 @@ -48,127 +61,6 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( usrp2_clock_ctrl::sptr clk_ctrl ); -/*! - * 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 get_t; - typedef boost::function set_t; - typedef boost::shared_ptr 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 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 _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 _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 _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. @@ -176,12 +68,7 @@ private: */ 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 dsp_xports; - std::vector 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_dsps; + tx_dsp_core_200::sptr tx_dsp; + time64_core_200::sptr time64; + std::vector dsp_xports; + std::vector 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 _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 _mboards; - uhd::dict _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 */ -- cgit v1.2.3