2010-10-17 01:07:10 +00:00
//
2016-08-02 01:17:41 +00:00
// Copyright 2010-2016 Ettus Research LLC
2010-10-17 01:07:10 +00:00
//
// 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/>.
//
2011-06-29 02:10:55 +00:00
# include <uhd/property_tree.hpp>
2010-10-17 01:07:10 +00:00
# include <uhd/usrp/multi_usrp.hpp>
2011-05-05 02:53:01 +00:00
# include <uhd/utils/msg.hpp>
2011-02-24 22:54:24 +00:00
# include <uhd/exception.hpp>
2013-07-15 22:48:51 +00:00
# include <uhd/utils/log.hpp>
2014-08-05 21:05:09 +00:00
# include <uhd/utils/math.hpp>
2010-10-17 01:07:10 +00:00
# include <uhd/utils/gain_group.hpp>
2012-04-05 00:03:35 +00:00
# include <uhd/usrp/dboard_id.hpp>
# include <uhd/usrp/mboard_eeprom.hpp>
# include <uhd/usrp/dboard_eeprom.hpp>
2014-02-28 17:14:31 +00:00
# include <uhd/convert.hpp>
2015-08-04 21:09:40 +00:00
# include <uhd/utils/soft_register.hpp>
2016-08-02 01:17:41 +00:00
# include "legacy_compat.hpp"
2012-04-05 00:03:35 +00:00
# include <boost/assign/list_of.hpp>
2010-10-17 01:07:10 +00:00
# include <boost/thread.hpp>
# include <boost/foreach.hpp>
# include <boost/format.hpp>
2015-01-30 23:11:15 +00:00
# include <boost/algorithm/string.hpp>
# include <algorithm>
2011-03-10 19:56:52 +00:00
# include <cmath>
2010-10-17 01:07:10 +00:00
using namespace uhd ;
using namespace uhd : : usrp ;
2010-10-20 23:20:36 +00:00
const std : : string multi_usrp : : ALL_GAINS = " " ;
2016-07-19 16:27:38 +00:00
const std : : string multi_usrp : : ALL_LOS = " all " ;
2010-10-20 23:20:36 +00:00
2014-02-22 02:08:56 +00:00
UHD_INLINE std : : string string_vector_to_string ( std : : vector < std : : string > values , std : : string delimiter = std : : string ( " " ) )
2014-01-30 23:20:49 +00:00
{
std : : string out = " " ;
for ( std : : vector < std : : string > : : iterator iter = values . begin ( ) ; iter ! = values . end ( ) ; iter + + )
2014-02-22 02:08:56 +00:00
{
out + = ( iter ! = values . begin ( ) ? delimiter : " " ) + * iter ;
}
2014-01-30 23:20:49 +00:00
return out ;
}
2014-02-22 02:08:56 +00:00
# define THROW_GAIN_NAME_ERROR(name,chan,dir) throw uhd::exception::runtime_error( \
( boost : : format ( " %s: gain \" %s \" not found for channel %d. \n Available gains: %s \n " ) % \
__FUNCTION__ % name % chan % string_vector_to_string ( get_ # # dir # # _gain_names ( chan ) ) ) . str ( ) ) ;
2010-10-17 01:07:10 +00:00
/***********************************************************************
2011-03-10 19:56:52 +00:00
* Helper methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-06-29 02:10:55 +00:00
static void do_samp_rate_warning_message (
2011-03-10 19:56:52 +00:00
double target_rate ,
double actual_rate ,
const std : : string & xx
) {
static const double max_allowed_error = 1.0 ; //Sps
if ( std : : abs ( target_rate - actual_rate ) > max_allowed_error ) {
2011-05-05 01:36:10 +00:00
UHD_MSG ( warning ) < < boost : : format (
2011-03-10 19:56:52 +00:00
" The hardware does not support the requested %s sample rate: \n "
" Target sample rate: %f MSps \n "
" Actual sample rate: %f MSps \n "
2011-05-05 01:36:10 +00:00
) % xx % ( target_rate / 1e6 ) % ( actual_rate / 1e6 ) ;
2011-03-10 19:56:52 +00:00
}
}
2015-08-14 18:59:27 +00:00
/*static void do_tune_freq_results_message(
2011-11-11 01:29:18 +00:00
const tune_request_t & tune_req ,
2014-08-05 21:05:09 +00:00
const tune_result_t & tune_result ,
2011-03-10 19:56:52 +00:00
double actual_freq ,
const std : : string & xx
) {
2014-08-05 21:05:09 +00:00
const double target_freq = tune_req . target_freq ;
const double clipped_target_freq = tune_result . clipped_rf_freq ;
const double target_rf_freq = tune_result . target_rf_freq ;
const double actual_rf_freq = tune_result . actual_rf_freq ;
const double target_dsp_freq = tune_result . target_dsp_freq ;
const double actual_dsp_freq = tune_result . actual_dsp_freq ;
2011-11-11 01:29:18 +00:00
if ( tune_req . rf_freq_policy = = tune_request_t : : POLICY_MANUAL ) return ;
2014-08-05 21:05:09 +00:00
if ( tune_req . dsp_freq_policy = = tune_request_t : : POLICY_MANUAL ) return ;
2011-11-11 01:29:18 +00:00
2014-08-05 21:05:09 +00:00
bool requested_freq_success = uhd : : math : : frequencies_are_equal ( target_freq , clipped_target_freq ) ;
bool target_freq_success = uhd : : math : : frequencies_are_equal ( clipped_target_freq , actual_freq ) ;
bool rf_lo_tune_success = uhd : : math : : frequencies_are_equal ( target_rf_freq , actual_rf_freq ) ;
bool dsp_tune_success = uhd : : math : : frequencies_are_equal ( target_dsp_freq , actual_dsp_freq ) ;
if ( requested_freq_success and target_freq_success and rf_lo_tune_success
and dsp_tune_success ) {
UHD_MSG ( status ) < < boost : : format (
" Successfully tuned to %f MHz \n \n " )
% ( actual_freq / 1e6 ) ;
} else {
boost : : format base_message ( " Tune Request: %f MHz \n " ) ;
base_message % ( target_freq / 1e6 ) ;
std : : string results_string = base_message . str ( ) ;
if ( requested_freq_success and ( not rf_lo_tune_success ) ) {
boost : : format rf_lo_message (
" The RF LO does not support the requested frequency: \n "
" Requested LO Frequency: %f MHz \n "
" RF LO Result: %f MHz \n "
" Attempted to use the DSP to reach the requested frequency: \n "
" Desired DSP Frequency: %f MHz \n "
" DSP Result: %f MHz \n "
" Successfully tuned to %f MHz \n \n " ) ;
rf_lo_message % ( target_rf_freq / 1e6 ) % ( actual_rf_freq / 1e6 )
% ( target_dsp_freq / 1e6 ) % ( actual_dsp_freq / 1e6 )
% ( actual_freq / 1e6 ) ;
results_string + = rf_lo_message . str ( ) ;
UHD_MSG ( status ) < < results_string ;
return ;
}
if ( not requested_freq_success ) {
boost : : format failure_message (
" The requested %s frequency is outside of the system range, and has been clipped: \n "
" Target Frequency: %f MHz \n "
" Clipped Target Frequency: %f MHz \n " ) ;
failure_message % xx % ( target_freq / 1e6 ) % ( clipped_target_freq / 1e6 ) ;
results_string + = failure_message . str ( ) ;
}
if ( not rf_lo_tune_success ) {
boost : : format rf_lo_message (
" The RF LO does not support the requested frequency: \n "
" Requested LO Frequency: %f MHz \n "
" RF LO Result: %f MHz \n "
" Attempted to use the DSP to reach the requested frequency: \n "
" Desired DSP Frequency: %f MHz \n "
" DSP Result: %f MHz \n " ) ;
rf_lo_message % ( target_rf_freq / 1e6 ) % ( actual_rf_freq / 1e6 )
% ( target_dsp_freq / 1e6 ) % ( actual_dsp_freq / 1e6 ) ;
results_string + = rf_lo_message . str ( ) ;
} else if ( not dsp_tune_success ) {
boost : : format dsp_message (
" The DSP does not support the requested frequency: \n "
" Requested DSP Frequency: %f MHz \n "
" DSP Result: %f MHz \n " ) ;
dsp_message % ( target_dsp_freq / 1e6 ) % ( actual_dsp_freq / 1e6 ) ;
results_string + = dsp_message . str ( ) ;
}
if ( target_freq_success ) {
boost : : format success_message (
" Successfully tuned to %f MHz \n \n " ) ;
success_message % ( actual_freq / 1e6 ) ;
results_string + = success_message . str ( ) ;
} else {
boost : : format failure_message (
" Failed to tune to target frequency \n "
" Target Frequency: %f MHz \n "
" Actual Frequency: %f MHz \n \n " ) ;
failure_message % ( clipped_target_freq / 1e6 ) % ( actual_freq / 1e6 ) ;
results_string + = failure_message . str ( ) ;
}
UHD_MSG ( warning ) < < results_string < < std : : endl ;
2011-03-10 19:56:52 +00:00
}
2015-08-14 18:59:27 +00:00
} */
2011-03-10 19:56:52 +00:00
2014-06-21 01:43:27 +00:00
/*! The CORDIC can be used to shift the baseband below / past the tunable
* limits of the actual RF front - end . The baseband filter , located on the
* daughterboard , however , limits the useful instantaneous bandwidth . We
* allow the user to tune to the edge of the filter , where the roll - off
* begins . This prevents the user from tuning past the point where less
* than half of the spectrum would be useful . */
2011-08-18 00:09:55 +00:00
static meta_range_t make_overall_tune_range (
const meta_range_t & fe_range ,
const meta_range_t & dsp_range ,
const double bw
) {
2011-08-29 16:43:54 +00:00
meta_range_t range ;
BOOST_FOREACH ( const range_t & sub_range , fe_range ) {
range . push_back ( range_t (
2013-08-23 22:16:52 +00:00
sub_range . start ( ) + std : : max ( dsp_range . start ( ) , - bw / 2 ) ,
sub_range . stop ( ) + std : : min ( dsp_range . stop ( ) , bw / 2 ) ,
2011-08-29 16:43:54 +00:00
dsp_range . step ( )
) ) ;
}
return range ;
2011-08-18 00:09:55 +00:00
}
2014-02-28 17:14:31 +00:00
2011-06-29 17:54:28 +00:00
/***********************************************************************
* Gain helper functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-08 17:08:43 +00:00
static double get_gain_value ( property_tree : : sptr subtree ) {
return subtree - > access < double > ( " value " ) . get ( ) ;
2011-06-29 02:10:55 +00:00
}
2011-07-08 17:08:43 +00:00
static void set_gain_value ( property_tree : : sptr subtree , const double gain ) {
subtree - > access < double > ( " value " ) . set ( gain ) ;
2011-06-29 02:10:55 +00:00
}
2011-07-08 17:08:43 +00:00
static meta_range_t get_gain_range ( property_tree : : sptr subtree ) {
return subtree - > access < meta_range_t > ( " range " ) . get ( ) ;
2011-06-29 02:10:55 +00:00
}
2011-07-08 17:08:43 +00:00
static gain_fcns_t make_gain_fcns_from_subtree ( property_tree : : sptr subtree ) {
2011-06-29 02:10:55 +00:00
gain_fcns_t gain_fcns ;
2011-07-08 17:08:43 +00:00
gain_fcns . get_range = boost : : bind ( & get_gain_range , subtree ) ;
gain_fcns . get_value = boost : : bind ( & get_gain_value , subtree ) ;
gain_fcns . set_value = boost : : bind ( & set_gain_value , subtree , _1 ) ;
2011-06-29 02:10:55 +00:00
return gain_fcns ;
}
2011-06-29 17:54:28 +00:00
/***********************************************************************
* Tune Helper Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const double RX_SIGN = + 1.0 ;
static const double TX_SIGN = - 1.0 ;
static tune_result_t tune_xx_subdev_and_dsp (
const double xx_sign ,
2011-07-08 17:08:43 +00:00
property_tree : : sptr dsp_subtree ,
property_tree : : sptr rf_fe_subtree ,
2011-06-29 17:54:28 +00:00
const tune_request_t & tune_request
) {
//------------------------------------------------------------------
2014-08-05 21:05:09 +00:00
//-- calculate the tunable frequency ranges of the system
2014-06-21 01:43:27 +00:00
//------------------------------------------------------------------
freq_range_t tune_range = make_overall_tune_range (
rf_fe_subtree - > access < meta_range_t > ( " freq/range " ) . get ( ) ,
dsp_subtree - > access < meta_range_t > ( " freq/range " ) . get ( ) ,
rf_fe_subtree - > access < double > ( " bandwidth/value " ) . get ( )
) ;
2014-08-05 21:05:09 +00:00
freq_range_t dsp_range = dsp_subtree - > access < meta_range_t > ( " freq/range " ) . get ( ) ;
2014-10-30 00:03:04 +00:00
freq_range_t rf_range = rf_fe_subtree - > access < meta_range_t > ( " freq/range " ) . get ( ) ;
2014-08-05 21:05:09 +00:00
double clipped_requested_freq = tune_range . clip ( tune_request . target_freq ) ;
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
2014-06-21 01:43:27 +00:00
//-- If the RF FE requires an LO offset, build it into the tune request
//------------------------------------------------------------------
/*! The automatically calculated LO offset is only used if the
* ' use_lo_offset ' field in the daughterboard property tree is set to TRUE ,
* and the tune policy is set to AUTO . To use an LO offset normally , the
* user should specify the MANUAL tune policy and lo_offset as part of the
* tune_request . This lo_offset is based on the requirements of the FE , and
* does not reflect a user - requested lo_offset , which is handled later . */
2011-06-29 17:54:28 +00:00
double lo_offset = 0.0 ;
2011-07-08 17:08:43 +00:00
if ( rf_fe_subtree - > access < bool > ( " use_lo_offset " ) . get ( ) ) {
2014-06-21 01:43:27 +00:00
// If the frontend has lo_offset value and range properties, trust it
// for lo_offset
if ( rf_fe_subtree - > exists ( " lo_offset/value " ) ) {
lo_offset = rf_fe_subtree - > access < double > ( " lo_offset/value " ) . get ( ) ;
}
2011-12-13 16:15:02 +00:00
2011-06-29 17:54:28 +00:00
//If the local oscillator will be in the passband, use an offset.
//But constrain the LO offset by the width of the filter bandwidth.
2011-07-08 17:08:43 +00:00
const double rate = dsp_subtree - > access < double > ( " rate/value " ) . get ( ) ;
const double bw = rf_fe_subtree - > access < double > ( " bandwidth/value " ) . get ( ) ;
2011-06-29 17:54:28 +00:00
if ( bw > rate ) lo_offset = std : : min ( ( bw - rate ) / 2 , rate / 2 ) ;
}
2012-11-09 02:46:57 +00:00
//------------------------------------------------------------------
//-- poke the tune request args into the dboard
//------------------------------------------------------------------
2014-08-05 21:05:09 +00:00
if ( rf_fe_subtree - > exists ( " tune_args " ) ) {
2012-11-09 02:46:57 +00:00
rf_fe_subtree - > access < device_addr_t > ( " tune_args " ) . set ( tune_request . args ) ;
}
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
//-- set the RF frequency depending upon the policy
//------------------------------------------------------------------
double target_rf_freq = 0.0 ;
2014-10-30 00:03:04 +00:00
2011-06-29 17:54:28 +00:00
switch ( tune_request . rf_freq_policy ) {
2014-06-21 01:43:27 +00:00
case tune_request_t : : POLICY_AUTO :
2014-08-05 21:05:09 +00:00
target_rf_freq = clipped_requested_freq + lo_offset ;
2014-06-21 01:43:27 +00:00
break ;
case tune_request_t : : POLICY_MANUAL :
// If the rf_fe understands lo_offset settings, infer the desired
2014-08-05 21:05:09 +00:00
// lo_offset and set it. Side effect: In TVRX2 for example, after
2014-06-21 01:43:27 +00:00
// setting the lo_offset (if_freq) with a POLICY_MANUAL, there is no
// way for the user to automatically get back to default if_freq
// without deconstruct/reconstruct the rf_fe objects.
if ( rf_fe_subtree - > exists ( " lo_offset/value " ) ) {
rf_fe_subtree - > access < double > ( " lo_offset/value " )
. set ( tune_request . rf_freq - tune_request . target_freq ) ;
}
2011-12-13 16:15:02 +00:00
2014-10-30 00:03:04 +00:00
target_rf_freq = rf_range . clip ( tune_request . rf_freq ) ;
2014-06-21 01:43:27 +00:00
break ;
2011-06-29 17:54:28 +00:00
2014-06-21 01:43:27 +00:00
case tune_request_t : : POLICY_NONE :
break ; //does not set
2011-06-29 17:54:28 +00:00
}
2014-08-05 21:05:09 +00:00
//------------------------------------------------------------------
//-- Tune the RF frontend
//------------------------------------------------------------------
2015-08-05 21:24:27 +00:00
if ( tune_request . rf_freq_policy ! = tune_request_t : : POLICY_NONE ) {
rf_fe_subtree - > access < double > ( " freq/value " ) . set ( target_rf_freq ) ;
}
2014-06-21 01:43:27 +00:00
const double actual_rf_freq = rf_fe_subtree - > access < double > ( " freq/value " ) . get ( ) ;
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
2014-08-05 21:05:09 +00:00
//-- Set the DSP frequency depending upon the DSP frequency policy.
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
2014-06-21 01:43:27 +00:00
double target_dsp_freq = 0.0 ;
2014-08-05 21:05:09 +00:00
switch ( tune_request . dsp_freq_policy ) {
2014-06-21 01:43:27 +00:00
case tune_request_t : : POLICY_AUTO :
/* If we are using the AUTO tuning policy, then we prevent the
* CORDIC from spinning us outside of the range of the baseband
* filter , regardless of what the user requested . This could happen
* if the user requested a center frequency so far outside of the
* tunable range of the FE that the CORDIC would spin outside the
* filtered baseband . */
2014-08-05 21:05:09 +00:00
target_dsp_freq = actual_rf_freq - clipped_requested_freq ;
2011-06-29 17:54:28 +00:00
2014-06-21 01:43:27 +00:00
//invert the sign on the dsp freq for transmit (spinning up vs down)
target_dsp_freq * = xx_sign ;
2011-06-29 17:54:28 +00:00
2014-06-21 01:43:27 +00:00
break ;
case tune_request_t : : POLICY_MANUAL :
/* If the user has specified a manual tune policy, we will allow
2014-08-05 21:05:09 +00:00
* tuning outside of the baseband filter , but will still clip the
* target DSP frequency to within the bounds of the CORDIC to
* prevent undefined behavior ( likely an overflow ) . */
2014-06-21 01:43:27 +00:00
target_dsp_freq = dsp_range . clip ( tune_request . dsp_freq ) ;
break ;
case tune_request_t : : POLICY_NONE :
break ; //does not set
2011-06-29 17:54:28 +00:00
}
2014-06-21 01:43:27 +00:00
2014-08-05 21:05:09 +00:00
//------------------------------------------------------------------
//-- Tune the DSP
//------------------------------------------------------------------
2015-08-05 21:24:27 +00:00
if ( tune_request . dsp_freq_policy ! = tune_request_t : : POLICY_NONE ) {
dsp_subtree - > access < double > ( " freq/value " ) . set ( target_dsp_freq ) ;
}
2011-07-08 17:08:43 +00:00
const double actual_dsp_freq = dsp_subtree - > access < double > ( " freq/value " ) . get ( ) ;
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
2014-08-05 21:05:09 +00:00
//-- Load and return the tune result
2011-06-29 17:54:28 +00:00
//------------------------------------------------------------------
tune_result_t tune_result ;
2014-08-05 21:05:09 +00:00
tune_result . clipped_rf_freq = clipped_requested_freq ;
2011-06-29 17:54:28 +00:00
tune_result . target_rf_freq = target_rf_freq ;
tune_result . actual_rf_freq = actual_rf_freq ;
tune_result . target_dsp_freq = target_dsp_freq ;
tune_result . actual_dsp_freq = actual_dsp_freq ;
return tune_result ;
}
static double derive_freq_from_xx_subdev_and_dsp (
const double xx_sign ,
2011-07-08 17:08:43 +00:00
property_tree : : sptr dsp_subtree ,
property_tree : : sptr rf_fe_subtree
2011-06-29 17:54:28 +00:00
) {
//extract actual dsp and IF frequencies
2011-07-08 17:08:43 +00:00
const double actual_rf_freq = rf_fe_subtree - > access < double > ( " freq/value " ) . get ( ) ;
const double actual_dsp_freq = dsp_subtree - > access < double > ( " freq/value " ) . get ( ) ;
2011-06-29 17:54:28 +00:00
//invert the sign on the dsp freq for transmit
return actual_rf_freq - actual_dsp_freq * xx_sign ;
}
2011-03-10 19:56:52 +00:00
/***********************************************************************
* Multi USRP Implementation
2010-10-17 01:07:10 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class multi_usrp_impl : public multi_usrp {
public :
multi_usrp_impl ( const device_addr_t & addr ) {
2014-07-17 18:50:50 +00:00
_dev = device : : make ( addr , device : : USRP ) ;
2011-09-14 17:14:29 +00:00
_tree = _dev - > get_tree ( ) ;
2016-08-02 01:17:41 +00:00
_is_device3 = bool ( boost : : dynamic_pointer_cast < uhd : : device3 > ( _dev ) ) ;
if ( is_device3 ( ) ) {
_legacy_compat = rfnoc : : legacy_compat : : make ( get_device3 ( ) , addr ) ;
}
2010-10-17 01:07:10 +00:00
}
device : : sptr get_device ( void ) {
return _dev ;
}
2016-08-02 01:17:41 +00:00
bool is_device3 ( void ) {
return _is_device3 ;
}
device3 : : sptr get_device3 ( void ) {
if ( not is_device3 ( ) ) {
throw uhd : : type_error ( " Cannot call get_device3() on a non-generation 3 device. " ) ;
}
return boost : : dynamic_pointer_cast < uhd : : device3 > ( _dev ) ;
}
2012-04-05 00:03:35 +00:00
dict < std : : string , std : : string > get_usrp_rx_info ( size_t chan ) {
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
dict < std : : string , std : : string > usrp_info ;
mboard_eeprom_t mb_eeprom = _tree - > access < mboard_eeprom_t > ( mb_root ( mcp . mboard ) / " eeprom " ) . get ( ) ;
2014-12-19 02:45:48 +00:00
dboard_eeprom_t db_eeprom = _tree - > access < dboard_eeprom_t > ( rx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " rx_eeprom " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_id " ] = _tree - > access < std : : string > ( mb_root ( mcp . mboard ) / " name " ) . get ( ) ;
usrp_info [ " mboard_name " ] = mb_eeprom [ " name " ] ;
usrp_info [ " mboard_serial " ] = mb_eeprom [ " serial " ] ;
usrp_info [ " rx_id " ] = db_eeprom . id . to_pp_string ( ) ;
2014-12-19 02:45:48 +00:00
usrp_info [ " rx_subdev_name " ] = _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " name " ) . get ( ) ;
2012-04-05 17:40:07 +00:00
usrp_info [ " rx_subdev_spec " ] = _tree - > access < subdev_spec_t > ( mb_root ( mcp . mboard ) / " rx_subdev_spec " ) . get ( ) . to_string ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " rx_serial " ] = db_eeprom . serial ;
2014-12-19 02:45:48 +00:00
usrp_info [ " rx_antenna " ] = _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
return usrp_info ;
}
dict < std : : string , std : : string > get_usrp_tx_info ( size_t chan ) {
mboard_chan_pair mcp = tx_chan_to_mcp ( chan ) ;
dict < std : : string , std : : string > usrp_info ;
mboard_eeprom_t mb_eeprom = _tree - > access < mboard_eeprom_t > ( mb_root ( mcp . mboard ) / " eeprom " ) . get ( ) ;
2014-12-19 02:45:48 +00:00
dboard_eeprom_t db_eeprom = _tree - > access < dboard_eeprom_t > ( tx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " tx_eeprom " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_id " ] = _tree - > access < std : : string > ( mb_root ( mcp . mboard ) / " name " ) . get ( ) ;
usrp_info [ " mboard_name " ] = mb_eeprom [ " name " ] ;
usrp_info [ " mboard_serial " ] = mb_eeprom [ " serial " ] ;
usrp_info [ " tx_id " ] = db_eeprom . id . to_pp_string ( ) ;
2014-12-19 02:45:48 +00:00
usrp_info [ " tx_subdev_name " ] = _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " name " ) . get ( ) ;
2012-04-05 17:40:07 +00:00
usrp_info [ " tx_subdev_spec " ] = _tree - > access < subdev_spec_t > ( mb_root ( mcp . mboard ) / " tx_subdev_spec " ) . get ( ) . to_string ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " tx_serial " ] = db_eeprom . serial ;
2014-12-19 02:45:48 +00:00
usrp_info [ " tx_antenna " ] = _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
return usrp_info ;
}
2010-10-17 01:07:10 +00:00
/*******************************************************************
* Mboard methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-02-01 00:29:12 +00:00
void set_master_clock_rate ( double rate , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2015-09-17 23:45:41 +00:00
if ( _tree - > exists ( mb_root ( mboard ) / " auto_tick_rate " )
and _tree - > access < bool > ( mb_root ( mboard ) / " auto_tick_rate " ) . get ( ) ) {
2014-11-21 14:08:31 +00:00
_tree - > access < bool > ( mb_root ( mboard ) / " auto_tick_rate " ) . set ( false ) ;
2015-09-17 23:45:41 +00:00
UHD_MSG ( status ) < < " Setting master clock rate selection to 'manual'. " < < std : : endl ;
2014-11-21 14:08:31 +00:00
}
2011-06-29 02:10:55 +00:00
_tree - > access < double > ( mb_root ( mboard ) / " tick_rate " ) . set ( rate ) ;
2011-02-01 00:29:12 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_master_clock_rate ( rate , m ) ;
}
}
double get_master_clock_rate ( size_t mboard ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < double > ( mb_root ( mboard ) / " tick_rate " ) . get ( ) ;
2011-02-01 00:29:12 +00:00
}
2010-10-17 01:07:10 +00:00
std : : string get_pp_string ( void ) {
2011-06-29 18:03:20 +00:00
std : : string buff = str ( boost : : format (
" %s USRP: \n "
" Device: %s \n "
)
% ( ( get_num_mboards ( ) > 1 ) ? " Multi " : " Single " )
% ( _tree - > access < std : : string > ( " /name " ) . get ( ) )
) ;
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
buff + = str ( boost : : format (
" Mboard %d: %s \n "
) % m
% ( _tree - > access < std : : string > ( mb_root ( m ) / " name " ) . get ( ) )
) ;
}
//----------- rx side of life ----------------------------------
for ( size_t m = 0 , chan = 0 ; m < get_num_mboards ( ) ; m + + ) {
for ( ; chan < ( m + 1 ) * get_rx_subdev_spec ( m ) . size ( ) ; chan + + ) {
buff + = str ( boost : : format (
" RX Channel: %u \n "
" RX DSP: %s \n "
" RX Dboard: %s \n "
" RX Subdev: %s \n "
) % chan
% rx_dsp_root ( chan ) . leaf ( )
% rx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) . leaf ( )
% ( _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " name " ) . get ( ) )
) ;
}
}
//----------- tx side of life ----------------------------------
for ( size_t m = 0 , chan = 0 ; m < get_num_mboards ( ) ; m + + ) {
for ( ; chan < ( m + 1 ) * get_tx_subdev_spec ( m ) . size ( ) ; chan + + ) {
buff + = str ( boost : : format (
" TX Channel: %u \n "
" TX DSP: %s \n "
" TX Dboard: %s \n "
" TX Subdev: %s \n "
) % chan
% tx_dsp_root ( chan ) . leaf ( )
% tx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) . leaf ( )
% ( _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " name " ) . get ( ) )
) ;
}
}
return buff ;
2010-10-17 01:07:10 +00:00
}
std : : string get_mboard_name ( size_t mboard ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : string > ( mb_root ( mboard ) / " name " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-11 18:29:59 +00:00
time_spec_t get_time_now ( size_t mboard = 0 ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/now " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-11 18:29:59 +00:00
time_spec_t get_time_last_pps ( size_t mboard = 0 ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/pps " ) . get ( ) ;
2010-12-31 00:41:38 +00:00
}
2011-01-27 23:24:47 +00:00
void set_time_now ( const time_spec_t & time_spec , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2011-06-29 02:10:55 +00:00
_tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/now " ) . set ( time_spec ) ;
2011-01-27 23:24:47 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_time_now ( time_spec , m ) ;
}
}
2011-12-12 20:49:40 +00:00
void set_time_next_pps ( const time_spec_t & time_spec , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
_tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/pps " ) . set ( time_spec ) ;
return ;
}
2010-10-17 01:07:10 +00:00
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
2011-12-12 20:49:40 +00:00
set_time_next_pps ( time_spec , m ) ;
2010-10-17 01:07:10 +00:00
}
}
void set_time_unknown_pps ( const time_spec_t & time_spec ) {
2011-05-05 02:53:01 +00:00
UHD_MSG ( status ) < < " 1) catch time transition at pps edge " < < std : : endl ;
2014-08-09 00:40:54 +00:00
boost : : system_time end_time = boost : : get_system_time ( ) + boost : : posix_time : : milliseconds ( 1100 ) ;
2010-12-31 00:41:38 +00:00
time_spec_t time_start_last_pps = get_time_last_pps ( ) ;
2014-08-09 00:40:54 +00:00
while ( time_start_last_pps = = get_time_last_pps ( ) )
{
if ( boost : : get_system_time ( ) > end_time )
{
2011-02-25 00:35:29 +00:00
throw uhd : : runtime_error (
2011-01-07 20:07:06 +00:00
" Board 0 may not be getting a PPS signal! \n "
" No PPS detected within the time interval. \n "
" See the application notes for your device. \n "
2010-12-31 00:41:38 +00:00
) ;
}
2014-08-09 00:40:54 +00:00
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 1 ) ) ;
2010-10-17 01:07:10 +00:00
}
2011-05-05 02:53:01 +00:00
UHD_MSG ( status ) < < " 2) set times next pps (synchronously) " < < std : : endl ;
2011-12-12 20:49:40 +00:00
set_time_next_pps ( time_spec , ALL_MBOARDS ) ;
2010-10-17 01:07:10 +00:00
boost : : this_thread : : sleep ( boost : : posix_time : : seconds ( 1 ) ) ;
//verify that the time registers are read to be within a few RTT
for ( size_t m = 1 ; m < get_num_mboards ( ) ; m + + ) {
2011-06-29 02:10:55 +00:00
time_spec_t time_0 = this - > get_time_now ( 0 ) ;
time_spec_t time_i = this - > get_time_now ( m ) ;
2010-10-17 01:07:10 +00:00
if ( time_i < time_0 or ( time_i - time_0 ) > time_spec_t ( 0.01 ) ) { //10 ms: greater than RTT but not too big
2011-05-05 01:36:10 +00:00
UHD_MSG ( warning ) < < boost : : format (
2010-10-17 01:07:10 +00:00
" Detected time deviation between board %d and board 0. \n "
" Board 0 time is %f seconds. \n "
" Board %d time is %f seconds. \n "
2011-05-05 01:36:10 +00:00
) % m % time_0 . get_real_secs ( ) % m % time_i . get_real_secs ( ) ;
2010-10-17 01:07:10 +00:00
}
}
}
2010-10-27 17:45:15 +00:00
bool get_time_synchronized ( void ) {
for ( size_t m = 1 ; m < get_num_mboards ( ) ; m + + ) {
2011-06-29 02:10:55 +00:00
time_spec_t time_0 = this - > get_time_now ( 0 ) ;
time_spec_t time_i = this - > get_time_now ( m ) ;
2010-10-27 17:45:15 +00:00
if ( time_i < time_0 or ( time_i - time_0 ) > time_spec_t ( 0.01 ) ) return false ;
}
return true ;
}
2012-03-02 02:35:12 +00:00
void set_command_time ( const time_spec_t & time_spec , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2012-03-12 01:35:52 +00:00
if ( not _tree - > exists ( mb_root ( mboard ) / " time/cmd " ) ) {
throw uhd : : not_implemented_error ( " timed command feature not implemented on this hardware " ) ;
}
2012-03-02 02:35:12 +00:00
_tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/cmd " ) . set ( time_spec ) ;
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_command_time ( time_spec , m ) ;
}
2011-11-04 03:29:18 +00:00
}
2012-03-02 02:35:12 +00:00
void clear_command_time ( size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
_tree - > access < time_spec_t > ( mb_root ( mboard ) / " time/cmd " ) . set ( time_spec_t ( 0.0 ) ) ;
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
clear_command_time ( m ) ;
}
2011-10-26 01:04:32 +00:00
}
2011-02-18 00:44:31 +00:00
void issue_stream_cmd ( const stream_cmd_t & stream_cmd , size_t chan ) {
if ( chan ! = ALL_CHANS ) {
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
_legacy_compat - > issue_stream_cmd ( stream_cmd , mcp . mboard , mcp . chan ) ;
} else {
_tree - > access < stream_cmd_t > ( rx_dsp_root ( chan ) / " stream_cmd " ) . set ( stream_cmd ) ;
}
2011-02-18 00:44:31 +00:00
return ;
}
2011-02-18 02:55:55 +00:00
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
2011-02-18 00:44:31 +00:00
issue_stream_cmd ( stream_cmd , c ) ;
2010-10-17 01:07:10 +00:00
}
}
void set_clock_config ( const clock_config_t & clock_config , size_t mboard ) {
2011-10-12 16:59:41 +00:00
//set the reference source...
std : : string clock_source ;
switch ( clock_config . ref_source ) {
case clock_config_t : : REF_INT : clock_source = " internal " ; break ;
2012-04-06 19:07:15 +00:00
case clock_config_t : : REF_SMA : clock_source = " external " ; break ;
case clock_config_t : : REF_MIMO : clock_source = " mimo " ; break ;
2011-10-12 16:59:41 +00:00
default : clock_source = " unknown " ;
}
this - > set_clock_source ( clock_source , mboard ) ;
//set the time source
std : : string time_source ;
switch ( clock_config . pps_source ) {
case clock_config_t : : PPS_INT : time_source = " internal " ; break ;
case clock_config_t : : PPS_SMA : time_source = " external " ; break ;
case clock_config_t : : PPS_MIMO : time_source = " mimo " ; break ;
default : time_source = " unknown " ;
}
if ( time_source = = " external " and clock_config . pps_polarity = = clock_config_t : : PPS_NEG ) time_source = " _external_ " ;
this - > set_time_source ( time_source , mboard ) ;
}
void set_time_source ( const std : : string & source , const size_t mboard ) {
2010-10-17 01:07:10 +00:00
if ( mboard ! = ALL_MBOARDS ) {
2011-10-12 16:59:41 +00:00
_tree - > access < std : : string > ( mb_root ( mboard ) / " time_source " / " value " ) . set ( source ) ;
2010-10-17 01:07:10 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
2012-03-12 19:10:41 +00:00
this - > set_time_source ( source , m ) ;
2010-10-17 01:07:10 +00:00
}
}
2011-10-12 16:59:41 +00:00
std : : string get_time_source ( const size_t mboard ) {
return _tree - > access < std : : string > ( mb_root ( mboard ) / " time_source " / " value " ) . get ( ) ;
}
std : : vector < std : : string > get_time_sources ( const size_t mboard ) {
return _tree - > access < std : : vector < std : : string > > ( mb_root ( mboard ) / " time_source " / " options " ) . get ( ) ;
}
void set_clock_source ( const std : : string & source , const size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
_tree - > access < std : : string > ( mb_root ( mboard ) / " clock_source " / " value " ) . set ( source ) ;
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
2012-03-12 19:10:41 +00:00
this - > set_clock_source ( source , m ) ;
2011-10-12 16:59:41 +00:00
}
}
std : : string get_clock_source ( const size_t mboard ) {
return _tree - > access < std : : string > ( mb_root ( mboard ) / " clock_source " / " value " ) . get ( ) ;
}
std : : vector < std : : string > get_clock_sources ( const size_t mboard ) {
return _tree - > access < std : : vector < std : : string > > ( mb_root ( mboard ) / " clock_source " / " options " ) . get ( ) ;
}
2014-02-04 19:04:07 +00:00
void set_clock_source_out ( const bool enb , const size_t mboard )
{
if ( mboard ! = ALL_MBOARDS )
{
if ( _tree - > exists ( mb_root ( mboard ) / " clock_source " / " output " ) )
{
_tree - > access < bool > ( mb_root ( mboard ) / " clock_source " / " output " ) . set ( enb ) ;
}
else
{
throw uhd : : runtime_error ( " multi_usrp::set_clock_source_out - not supported on this device " ) ;
}
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + )
{
this - > set_clock_source_out ( enb , m ) ;
}
}
void set_time_source_out ( const bool enb , const size_t mboard )
{
if ( mboard ! = ALL_MBOARDS )
{
if ( _tree - > exists ( mb_root ( mboard ) / " time_source " / " output " ) )
{
_tree - > access < bool > ( mb_root ( mboard ) / " time_source " / " output " ) . set ( enb ) ;
}
else
{
throw uhd : : runtime_error ( " multi_usrp::set_time_source_out - not supported on this device " ) ;
}
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + )
{
this - > set_time_source_out ( enb , m ) ;
}
}
2010-10-17 01:07:10 +00:00
size_t get_num_mboards ( void ) {
2011-06-29 02:10:55 +00:00
return _tree - > list ( " /mboards " ) . size ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-12 02:07:24 +00:00
sensor_value_t get_mboard_sensor ( const std : : string & name , size_t mboard ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < sensor_value_t > ( mb_root ( mboard ) / " sensors " / name ) . get ( ) ;
2011-02-12 02:07:24 +00:00
}
std : : vector < std : : string > get_mboard_sensor_names ( size_t mboard ) {
2011-06-29 02:10:55 +00:00
return _tree - > list ( mb_root ( mboard ) / " sensors " ) ;
2011-02-12 02:07:24 +00:00
}
2011-06-29 02:10:55 +00:00
2016-10-31 21:30:52 +00:00
void set_user_register ( const uint8_t addr , const uint32_t data , size_t mboard ) {
2012-01-29 01:21:40 +00:00
if ( mboard ! = ALL_MBOARDS ) {
2016-10-31 21:30:52 +00:00
typedef std : : pair < uint8_t , uint32_t > user_reg_t ;
2012-03-22 01:13:36 +00:00
_tree - > access < user_reg_t > ( mb_root ( mboard ) / " user/regs " ) . set ( user_reg_t ( addr , data ) ) ;
2012-01-29 01:21:40 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_user_register ( addr , data , m ) ;
}
}
2010-10-17 01:07:10 +00:00
/*******************************************************************
* RX methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-28 17:14:31 +00:00
rx_streamer : : sptr get_rx_stream ( const stream_args_t & args ) {
_check_link_rate ( args , false ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > get_rx_stream ( args ) ;
}
2014-02-28 17:14:31 +00:00
return this - > get_device ( ) - > get_rx_stream ( args ) ;
}
2010-10-17 01:07:10 +00:00
void set_rx_subdev_spec ( const subdev_spec_t & spec , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2011-06-29 02:10:55 +00:00
_tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " rx_subdev_spec " ) . set ( spec ) ;
2010-10-17 01:07:10 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_rx_subdev_spec ( spec , m ) ;
}
}
2013-07-15 22:48:51 +00:00
subdev_spec_t get_rx_subdev_spec ( size_t mboard )
{
subdev_spec_t spec = _tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " rx_subdev_spec " ) . get ( ) ;
if ( spec . empty ( ) )
{
try
{
const std : : string db_name = _tree - > list ( mb_root ( mboard ) / " dboards " ) . at ( 0 ) ;
const std : : string fe_name = _tree - > list ( mb_root ( mboard ) / " dboards " / db_name / " rx_frontends " ) . at ( 0 ) ;
spec . push_back ( subdev_spec_pair_t ( db_name , fe_name ) ) ;
_tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " rx_subdev_spec " ) . set ( spec ) ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::get_rx_subdev_spec(%u) failed to make default spec - %s " ) % mboard % e . what ( ) ) ) ;
}
UHD_MSG ( status ) < < " Selecting default RX front end spec: " < < spec . to_pp_string ( ) < < std : : endl ;
}
return spec ;
2010-10-17 01:07:10 +00:00
}
size_t get_rx_num_channels ( void ) {
2011-02-18 07:06:48 +00:00
size_t sum = 0 ;
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
sum + = get_rx_subdev_spec ( m ) . size ( ) ;
}
return sum ;
2010-10-17 01:07:10 +00:00
}
std : : string get_rx_subdev_name ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " name " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-18 02:55:55 +00:00
void set_rx_rate ( double rate , size_t chan ) {
2016-11-15 20:13:43 +00:00
if ( is_device3 ( ) ) {
_legacy_compat - > set_rx_rate ( rate , chan ) ;
if ( chan = = ALL_CHANS ) {
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
do_samp_rate_warning_message ( rate , get_rx_rate ( c ) , " RX " ) ;
}
} else {
do_samp_rate_warning_message ( rate , get_rx_rate ( chan ) , " RX " ) ;
}
return ;
}
2011-02-18 00:44:31 +00:00
if ( chan ! = ALL_CHANS ) {
2011-06-29 02:10:55 +00:00
_tree - > access < double > ( rx_dsp_root ( chan ) / " rate " / " value " ) . set ( rate ) ;
2011-02-18 00:44:31 +00:00
do_samp_rate_warning_message ( rate , get_rx_rate ( chan ) , " RX " ) ;
return ;
}
2011-02-18 02:55:55 +00:00
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
2011-02-18 00:44:31 +00:00
set_rx_rate ( rate , c ) ;
2010-10-17 01:07:10 +00:00
}
}
2011-02-18 00:44:31 +00:00
double get_rx_rate ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < double > ( rx_dsp_root ( chan ) / " rate " / " value " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-10-16 17:43:48 +00:00
meta_range_t get_rx_rates ( size_t chan ) {
return _tree - > access < meta_range_t > ( rx_dsp_root ( chan ) / " rate " / " range " ) . get ( ) ;
}
2010-10-25 20:41:40 +00:00
tune_result_t set_rx_freq ( const tune_request_t & tune_request , size_t chan ) {
2014-08-05 21:05:09 +00:00
tune_result_t result = tune_xx_subdev_and_dsp ( RX_SIGN ,
2014-06-21 01:43:27 +00:00
_tree - > subtree ( rx_dsp_root ( chan ) ) ,
_tree - > subtree ( rx_rf_fe_root ( chan ) ) ,
2016-08-02 01:17:41 +00:00
tune_request ) ;
2015-08-05 21:25:37 +00:00
//do_tune_freq_results_message(tune_request, result, get_rx_freq(chan), "RX");
2014-08-05 21:05:09 +00:00
return result ;
2010-10-17 01:07:10 +00:00
}
double get_rx_freq ( size_t chan ) {
2011-07-08 17:08:43 +00:00
return derive_freq_from_xx_subdev_and_dsp ( RX_SIGN , _tree - > subtree ( rx_dsp_root ( chan ) ) , _tree - > subtree ( rx_rf_fe_root ( chan ) ) ) ;
2010-10-17 01:07:10 +00:00
}
freq_range_t get_rx_freq_range ( size_t chan ) {
2011-08-18 00:09:55 +00:00
return make_overall_tune_range (
_tree - > access < meta_range_t > ( rx_rf_fe_root ( chan ) / " freq " / " range " ) . get ( ) ,
_tree - > access < meta_range_t > ( rx_dsp_root ( chan ) / " freq " / " range " ) . get ( ) ,
this - > get_rx_bandwidth ( chan )
) ;
2010-10-17 01:07:10 +00:00
}
2012-05-10 19:14:59 +00:00
freq_range_t get_fe_rx_freq_range ( size_t chan ) {
return _tree - > access < meta_range_t > ( rx_rf_fe_root ( chan ) / " freq " / " range " ) . get ( ) ;
}
2016-07-19 16:27:38 +00:00
std : : vector < std : : string > get_rx_lo_names ( size_t chan = 0 ) {
std : : vector < std : : string > lo_names ;
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
BOOST_FOREACH ( const std : : string & name , _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
lo_names . push_back ( name ) ;
}
}
return lo_names ;
}
void set_rx_lo_source ( const std : : string & src , const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS ) ) {
//Special value ALL_LOS support atomically sets the source for all LOs
_tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS / " source " / " value " ) . set ( src ) ;
} else {
BOOST_FOREACH ( const std : : string & n , _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
this - > set_rx_lo_source ( src , n , chan ) ;
}
}
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
_tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " los " / name / " source " / " value " ) . set ( src ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
throw uhd : : runtime_error ( " This device does not support manual configuration of LOs " ) ;
}
}
const std : : string get_rx_lo_source ( const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
//Special value ALL_LOS support atomically sets the source for all LOs
return _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS / " source " / " value " ) . get ( ) ;
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " los " / name / " source " / " value " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
2016-08-06 02:00:20 +00:00
// If the daughterboard doesn't expose it's LO(s) then it can only be internal
return " internal " ;
2016-07-19 16:27:38 +00:00
}
}
std : : vector < std : : string > get_rx_lo_sources ( const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS ) ) {
//Special value ALL_LOS support atomically sets the source for all LOs
return _tree - > access < std : : vector < std : : string > > ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS / " source " / " options " ) . get ( ) ;
} else {
return std : : vector < std : : string > ( ) ;
}
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < std : : vector < std : : string > > ( rx_rf_fe_root ( chan ) / " los " / name / " source " / " options " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
2016-08-06 02:00:20 +00:00
// If the daughterboard doesn't expose it's LO(s) then it can only be internal
2016-08-02 01:17:41 +00:00
return std : : vector < std : : string > ( 1 , " internal " ) ;
2016-07-19 16:27:38 +00:00
}
}
void set_rx_lo_export_enabled ( bool enabled , const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS ) ) {
//Special value ALL_LOS support atomically sets the source for all LOs
_tree - > access < bool > ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS / " export " ) . set ( enabled ) ;
} else {
BOOST_FOREACH ( const std : : string & n , _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
this - > set_rx_lo_export_enabled ( enabled , n , chan ) ;
}
}
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
_tree - > access < bool > ( rx_rf_fe_root ( chan ) / " los " / name / " export " ) . set ( enabled ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
throw uhd : : runtime_error ( " This device does not support manual configuration of LOs " ) ;
}
}
bool get_rx_lo_export_enabled ( const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
//Special value ALL_LOS support atomically sets the source for all LOs
return _tree - > access < bool > ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS / " export " ) . get ( ) ;
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < bool > ( rx_rf_fe_root ( chan ) / " los " / name / " export " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
2016-08-06 02:00:20 +00:00
// If the daughterboard doesn't expose it's LO(s), assume it cannot export
return false ;
2016-07-19 16:27:38 +00:00
}
}
double set_rx_lo_freq ( double freq , const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
throw uhd : : runtime_error ( " LO frequency must be set for each stage individually " ) ;
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
_tree - > access < double > ( rx_rf_fe_root ( chan ) / " los " / name / " freq " / " value " ) . set ( freq ) ;
return _tree - > access < double > ( rx_rf_fe_root ( chan ) / " los " / name / " freq " / " value " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
throw uhd : : runtime_error ( " This device does not support manual configuration of LOs " ) ;
}
}
double get_rx_lo_freq ( const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
throw uhd : : runtime_error ( " LO frequency must be retrieved for each stage individually " ) ;
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < double > ( rx_rf_fe_root ( chan ) / " los " / name / " freq " / " value " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
2016-08-06 02:00:20 +00:00
// Return actual RF frequency if the daughterboard doesn't expose it's LO(s)
return _tree - > access < double > ( rx_rf_fe_root ( chan ) / " freq " / " value " ) . get ( ) ;
2016-07-19 16:27:38 +00:00
}
}
freq_range_t get_rx_lo_freq_range ( const std : : string & name = ALL_LOS , size_t chan = 0 ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
throw uhd : : runtime_error ( " LO frequency range must be retrieved for each stage individually " ) ;
} else {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < freq_range_t > ( rx_rf_fe_root ( chan ) / " los " / name / " freq " / " range " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
2016-08-06 02:00:20 +00:00
// Return the actual RF range if the daughterboard doesn't expose it's LO(s)
return _tree - > access < meta_range_t > ( rx_rf_fe_root ( chan ) / " freq " / " range " ) . get ( ) ;
2016-07-19 16:27:38 +00:00
}
}
2011-01-12 03:46:45 +00:00
void set_rx_gain ( double gain , const std : : string & name , size_t chan ) {
2015-03-05 23:24:46 +00:00
/* Check if any AGC mode is enable and if so warn the user */
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " gain " / " agc " ) ) {
bool agc = _tree - > access < bool > ( rx_rf_fe_root ( chan ) / " gain " / " agc " / " enable " ) . get ( ) ;
if ( agc ) {
UHD_MSG ( warning ) < < " AGC enabled for this channel. Setting will be ignored. " < < std : : endl ;
}
}
} else {
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
if ( _tree - > exists ( rx_rf_fe_root ( c ) / " gain " / " agc " ) ) {
bool agc = _tree - > access < bool > ( rx_rf_fe_root ( chan ) / " gain " / " agc " / " enable " ) . get ( ) ;
if ( agc ) {
UHD_MSG ( warning ) < < " AGC enabled for this channel. Setting will be ignored. " < < std : : endl ;
}
}
}
}
/* Apply gain setting.
* If device is in AGC mode it will ignore the setting . */
2014-01-30 23:20:49 +00:00
try {
return rx_gain_group ( chan ) - > set_value ( gain , name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , rx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-20 23:20:36 +00:00
}
2015-02-03 16:20:09 +00:00
void set_normalized_rx_gain ( double gain , size_t chan = 0 )
{
if ( gain > 1.0 | | gain < 0.0 ) {
throw uhd : : runtime_error ( " Normalized gain out of range, must be in [0, 1]. " ) ;
}
gain_range_t gain_range = get_rx_gain_range ( ALL_GAINS , chan ) ;
double abs_gain = ( gain * ( gain_range . stop ( ) - gain_range . start ( ) ) ) + gain_range . start ( ) ;
set_rx_gain ( abs_gain , ALL_GAINS , chan ) ;
}
2015-03-05 23:24:46 +00:00
void set_rx_agc ( bool enable , size_t chan = 0 )
{
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " gain " / " agc " / " enable " ) ) {
_tree - > access < bool > ( rx_rf_fe_root ( chan ) / " gain " / " agc " / " enable " ) . set ( enable ) ;
} else {
UHD_MSG ( warning ) < < " AGC is not available on this device. " < < std : : endl ;
}
return ;
}
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
this - > set_rx_agc ( enable , c ) ;
}
}
2011-01-12 03:46:45 +00:00
double get_rx_gain ( const std : : string & name , size_t chan ) {
2014-01-30 23:20:49 +00:00
try {
return rx_gain_group ( chan ) - > get_value ( name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , rx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-17 01:07:10 +00:00
}
2015-02-03 16:20:09 +00:00
double get_normalized_rx_gain ( size_t chan )
{
gain_range_t gain_range = get_rx_gain_range ( ALL_GAINS , chan ) ;
double gain_range_width = gain_range . stop ( ) - gain_range . start ( ) ;
// In case we have a device without a range of gains:
if ( gain_range_width = = 0.0 ) {
return 0 ;
}
double norm_gain = ( get_rx_gain ( ALL_GAINS , chan ) - gain_range . start ( ) ) / gain_range_width ;
// Avoid rounding errors:
if ( norm_gain > 1.0 ) return 1.0 ;
if ( norm_gain < 0.0 ) return 0.0 ;
return norm_gain ;
}
2010-10-20 23:20:36 +00:00
gain_range_t get_rx_gain_range ( const std : : string & name , size_t chan ) {
2014-01-30 23:20:49 +00:00
try {
return rx_gain_group ( chan ) - > get_range ( name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , rx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-17 01:07:10 +00:00
}
2010-10-20 23:20:36 +00:00
std : : vector < std : : string > get_rx_gain_names ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return rx_gain_group ( chan ) - > get_names ( ) ;
2010-10-17 01:07:10 +00:00
}
void set_rx_antenna ( const std : : string & ant , size_t chan ) {
2011-06-29 02:10:55 +00:00
_tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " antenna " / " value " ) . set ( ant ) ;
2010-10-17 01:07:10 +00:00
}
std : : string get_rx_antenna ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
std : : vector < std : : string > get_rx_antennas ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : vector < std : : string > > ( rx_rf_fe_root ( chan ) / " antenna " / " options " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2010-10-19 22:42:21 +00:00
void set_rx_bandwidth ( double bandwidth , size_t chan ) {
2011-06-29 02:10:55 +00:00
_tree - > access < double > ( rx_rf_fe_root ( chan ) / " bandwidth " / " value " ) . set ( bandwidth ) ;
2010-10-19 22:42:21 +00:00
}
double get_rx_bandwidth ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < double > ( rx_rf_fe_root ( chan ) / " bandwidth " / " value " ) . get ( ) ;
2010-10-19 22:42:21 +00:00
}
2011-10-26 17:21:11 +00:00
meta_range_t get_rx_bandwidth_range ( size_t chan ) {
return _tree - > access < meta_range_t > ( rx_rf_fe_root ( chan ) / " bandwidth " / " range " ) . get ( ) ;
}
2010-10-17 01:07:10 +00:00
dboard_iface : : sptr get_rx_dboard_iface ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < dboard_iface : : sptr > ( rx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " iface " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-12 02:07:24 +00:00
sensor_value_t get_rx_sensor ( const std : : string & name , size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < sensor_value_t > ( rx_rf_fe_root ( chan ) / " sensors " / name ) . get ( ) ;
2011-02-12 02:07:24 +00:00
}
std : : vector < std : : string > get_rx_sensor_names ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > list ( rx_rf_fe_root ( chan ) / " sensors " ) ;
2011-02-12 02:07:24 +00:00
}
2011-10-21 23:38:27 +00:00
void set_rx_dc_offset ( const bool enb , size_t chan ) {
if ( chan ! = ALL_CHANS ) {
2014-04-30 12:19:21 +00:00
if ( _tree - > exists ( rx_fe_root ( chan ) / " dc_offset " / " enable " ) ) {
_tree - > access < bool > ( rx_fe_root ( chan ) / " dc_offset " / " enable " ) . set ( enb ) ;
2015-02-20 18:49:53 +00:00
} else if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " dc_offset " / " enable " ) ) {
/*For B2xx devices the dc-offset correction is implemented in the rf front-end*/
_tree - > access < bool > ( rx_rf_fe_root ( chan ) / " dc_offset " / " enable " ) . set ( enb ) ;
2014-04-30 12:19:21 +00:00
} else {
UHD_MSG ( warning ) < < " Setting DC offset compensation is not possible on this device. " < < std : : endl ;
}
2011-10-21 23:38:27 +00:00
return ;
}
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
this - > set_rx_dc_offset ( enb , c ) ;
}
}
void set_rx_dc_offset ( const std : : complex < double > & offset , size_t chan ) {
if ( chan ! = ALL_CHANS ) {
2014-04-30 12:19:21 +00:00
if ( _tree - > exists ( rx_fe_root ( chan ) / " dc_offset " / " value " ) ) {
_tree - > access < std : : complex < double > > ( rx_fe_root ( chan ) / " dc_offset " / " value " ) . set ( offset ) ;
} else {
UHD_MSG ( warning ) < < " Setting DC offset is not possible on this device. " < < std : : endl ;
}
2011-10-21 23:38:27 +00:00
return ;
}
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
this - > set_rx_dc_offset ( offset , c ) ;
}
}
2015-02-20 18:49:53 +00:00
void set_rx_iq_balance ( const bool enb , size_t chan ) {
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " iq_balance " / " enable " ) ) {
_tree - > access < bool > ( rx_rf_fe_root ( chan ) / " iq_balance " / " enable " ) . set ( enb ) ;
} else {
UHD_MSG ( warning ) < < " Setting IQ imbalance compensation is not possible on this device. " < < std : : endl ;
}
return ;
}
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
this - > set_rx_iq_balance ( enb , c ) ;
}
}
2011-10-24 17:36:41 +00:00
void set_rx_iq_balance ( const std : : complex < double > & offset , size_t chan ) {
2011-10-24 01:02:43 +00:00
if ( chan ! = ALL_CHANS ) {
2014-04-30 12:19:21 +00:00
if ( _tree - > exists ( rx_fe_root ( chan ) / " iq_balance " / " value " ) ) {
_tree - > access < std : : complex < double > > ( rx_fe_root ( chan ) / " iq_balance " / " value " ) . set ( offset ) ;
} else {
UHD_MSG ( warning ) < < " Setting IQ balance is not possible on this device. " < < std : : endl ;
}
2011-10-24 01:02:43 +00:00
return ;
}
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
2011-10-24 17:36:41 +00:00
this - > set_rx_iq_balance ( offset , c ) ;
2011-10-24 01:02:43 +00:00
}
}
2015-01-30 23:11:15 +00:00
std : : vector < std : : string > get_filter_names ( const std : : string & search_mask )
{
std : : vector < std : : string > ret ;
for ( size_t chan = 0 ; chan < get_rx_num_channels ( ) ; chan + + ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " filters " ) ) {
std : : vector < std : : string > names = _tree - > list ( rx_rf_fe_root ( chan ) / " filters " ) ;
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
{
std : : string name = rx_rf_fe_root ( chan ) / " filters " / names [ i ] ;
if ( ( search_mask . empty ( ) ) or boost : : contains ( name , search_mask ) ) {
ret . push_back ( name ) ;
}
}
}
if ( _tree - > exists ( rx_dsp_root ( chan ) / " filters " ) ) {
std : : vector < std : : string > names = _tree - > list ( rx_dsp_root ( chan ) / " filters " ) ;
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
{
std : : string name = rx_dsp_root ( chan ) / " filters " / names [ i ] ;
if ( ( search_mask . empty ( ) ) or ( boost : : contains ( name , search_mask ) ) ) {
ret . push_back ( name ) ;
}
}
}
}
for ( size_t chan = 0 ; chan < get_tx_num_channels ( ) ; chan + + ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " filters " ) ) {
std : : vector < std : : string > names = _tree - > list ( tx_rf_fe_root ( chan ) / " filters " ) ;
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
{
std : : string name = tx_rf_fe_root ( chan ) / " filters " / names [ i ] ;
if ( ( search_mask . empty ( ) ) or ( boost : : contains ( name , search_mask ) ) ) {
ret . push_back ( name ) ;
}
}
}
if ( _tree - > exists ( rx_dsp_root ( chan ) / " filters " ) ) {
std : : vector < std : : string > names = _tree - > list ( tx_dsp_root ( chan ) / " filters " ) ;
for ( size_t i = 0 ; i < names . size ( ) ; i + + )
{
std : : string name = tx_dsp_root ( chan ) / " filters " / names [ i ] ;
if ( ( search_mask . empty ( ) ) or ( boost : : contains ( name , search_mask ) ) ) {
ret . push_back ( name ) ;
}
}
}
}
return ret ;
}
filter_info_base : : sptr get_filter ( const std : : string & path )
{
std : : vector < std : : string > possible_names = get_filter_names ( " " ) ;
std : : vector < std : : string > : : iterator it ;
it = find ( possible_names . begin ( ) , possible_names . end ( ) , path ) ;
if ( it = = possible_names . end ( ) ) {
throw uhd : : runtime_error ( " Attempting to get non-existing filter: " + path ) ;
}
return _tree - > access < filter_info_base : : sptr > ( path / " value " ) . get ( ) ;
}
void set_filter ( const std : : string & path , filter_info_base : : sptr filter )
{
std : : vector < std : : string > possible_names = get_filter_names ( " " ) ;
std : : vector < std : : string > : : iterator it ;
it = find ( possible_names . begin ( ) , possible_names . end ( ) , path ) ;
if ( it = = possible_names . end ( ) ) {
throw uhd : : runtime_error ( " Attempting to set non-existing filter: " + path ) ;
}
_tree - > access < filter_info_base : : sptr > ( path / " value " ) . set ( filter ) ;
}
2010-10-17 01:07:10 +00:00
/*******************************************************************
* TX methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-28 17:14:31 +00:00
tx_streamer : : sptr get_tx_stream ( const stream_args_t & args ) {
_check_link_rate ( args , true ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > get_tx_stream ( args ) ;
}
2014-02-28 17:14:31 +00:00
return this - > get_device ( ) - > get_tx_stream ( args ) ;
}
2010-10-17 01:07:10 +00:00
void set_tx_subdev_spec ( const subdev_spec_t & spec , size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2011-06-29 02:10:55 +00:00
_tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " tx_subdev_spec " ) . set ( spec ) ;
2010-10-17 01:07:10 +00:00
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
set_tx_subdev_spec ( spec , m ) ;
}
}
2013-07-15 22:48:51 +00:00
subdev_spec_t get_tx_subdev_spec ( size_t mboard )
{
subdev_spec_t spec = _tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " tx_subdev_spec " ) . get ( ) ;
if ( spec . empty ( ) )
{
try
{
const std : : string db_name = _tree - > list ( mb_root ( mboard ) / " dboards " ) . at ( 0 ) ;
const std : : string fe_name = _tree - > list ( mb_root ( mboard ) / " dboards " / db_name / " tx_frontends " ) . at ( 0 ) ;
spec . push_back ( subdev_spec_pair_t ( db_name , fe_name ) ) ;
_tree - > access < subdev_spec_t > ( mb_root ( mboard ) / " tx_subdev_spec " ) . set ( spec ) ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::get_tx_subdev_spec(%u) failed to make default spec - %s " ) % mboard % e . what ( ) ) ) ;
}
UHD_MSG ( status ) < < " Selecting default TX front end spec: " < < spec . to_pp_string ( ) < < std : : endl ;
}
return spec ;
2010-10-17 01:07:10 +00:00
}
size_t get_tx_num_channels ( void ) {
2011-02-18 07:06:48 +00:00
size_t sum = 0 ;
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
sum + = get_tx_subdev_spec ( m ) . size ( ) ;
}
return sum ;
2010-10-17 01:07:10 +00:00
}
2012-04-05 00:03:35 +00:00
std : : string get_tx_subdev_name ( size_t chan ) {
return _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " name " ) . get ( ) ;
}
2011-02-18 02:55:55 +00:00
void set_tx_rate ( double rate , size_t chan ) {
2016-11-15 20:13:43 +00:00
if ( is_device3 ( ) ) {
_legacy_compat - > set_tx_rate ( rate , chan ) ;
if ( chan = = ALL_CHANS ) {
for ( size_t c = 0 ; c < get_tx_num_channels ( ) ; c + + ) {
do_samp_rate_warning_message ( rate , get_tx_rate ( c ) , " TX " ) ;
}
} else {
do_samp_rate_warning_message ( rate , get_tx_rate ( chan ) , " TX " ) ;
}
return ;
}
2011-02-18 00:44:31 +00:00
if ( chan ! = ALL_CHANS ) {
2011-06-29 02:10:55 +00:00
_tree - > access < double > ( tx_dsp_root ( chan ) / " rate " / " value " ) . set ( rate ) ;
2011-02-18 00:44:31 +00:00
do_samp_rate_warning_message ( rate , get_tx_rate ( chan ) , " TX " ) ;
return ;
}
2011-02-18 02:55:55 +00:00
for ( size_t c = 0 ; c < get_tx_num_channels ( ) ; c + + ) {
2011-02-18 00:44:31 +00:00
set_tx_rate ( rate , c ) ;
2010-10-17 01:07:10 +00:00
}
}
2011-02-18 00:44:31 +00:00
double get_tx_rate ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < double > ( tx_dsp_root ( chan ) / " rate " / " value " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-10-16 17:43:48 +00:00
meta_range_t get_tx_rates ( size_t chan ) {
return _tree - > access < meta_range_t > ( tx_dsp_root ( chan ) / " rate " / " range " ) . get ( ) ;
}
2010-10-25 20:41:40 +00:00
tune_result_t set_tx_freq ( const tune_request_t & tune_request , size_t chan ) {
2014-08-05 21:05:09 +00:00
tune_result_t result = tune_xx_subdev_and_dsp ( TX_SIGN ,
2014-06-21 01:43:27 +00:00
_tree - > subtree ( tx_dsp_root ( chan ) ) ,
_tree - > subtree ( tx_rf_fe_root ( chan ) ) ,
tune_request ) ;
2015-08-05 21:25:37 +00:00
//do_tune_freq_results_message(tune_request, result, get_tx_freq(chan), "TX");
2014-08-05 21:05:09 +00:00
return result ;
2010-10-17 01:07:10 +00:00
}
double get_tx_freq ( size_t chan ) {
2011-07-08 17:08:43 +00:00
return derive_freq_from_xx_subdev_and_dsp ( TX_SIGN , _tree - > subtree ( tx_dsp_root ( chan ) ) , _tree - > subtree ( tx_rf_fe_root ( chan ) ) ) ;
2010-10-17 01:07:10 +00:00
}
freq_range_t get_tx_freq_range ( size_t chan ) {
2011-08-18 00:09:55 +00:00
return make_overall_tune_range (
_tree - > access < meta_range_t > ( tx_rf_fe_root ( chan ) / " freq " / " range " ) . get ( ) ,
_tree - > access < meta_range_t > ( tx_dsp_root ( chan ) / " freq " / " range " ) . get ( ) ,
this - > get_tx_bandwidth ( chan )
) ;
2010-10-17 01:07:10 +00:00
}
2012-05-10 19:14:59 +00:00
freq_range_t get_fe_tx_freq_range ( size_t chan ) {
return _tree - > access < meta_range_t > ( tx_rf_fe_root ( chan ) / " freq " / " range " ) . get ( ) ;
}
2011-01-12 03:46:45 +00:00
void set_tx_gain ( double gain , const std : : string & name , size_t chan ) {
2014-01-30 23:20:49 +00:00
try {
return tx_gain_group ( chan ) - > set_value ( gain , name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , tx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-20 23:20:36 +00:00
}
2015-02-03 16:20:09 +00:00
void set_normalized_tx_gain ( double gain , size_t chan = 0 )
{
if ( gain > 1.0 | | gain < 0.0 ) {
throw uhd : : runtime_error ( " Normalized gain out of range, must be in [0, 1]. " ) ;
}
gain_range_t gain_range = get_tx_gain_range ( ALL_GAINS , chan ) ;
double abs_gain = ( gain * ( gain_range . stop ( ) - gain_range . start ( ) ) ) + gain_range . start ( ) ;
set_tx_gain ( abs_gain , ALL_GAINS , chan ) ;
}
2011-01-12 03:46:45 +00:00
double get_tx_gain ( const std : : string & name , size_t chan ) {
2014-01-30 23:20:49 +00:00
try {
return tx_gain_group ( chan ) - > get_value ( name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , tx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-17 01:07:10 +00:00
}
2015-02-03 16:20:09 +00:00
double get_normalized_tx_gain ( size_t chan )
{
gain_range_t gain_range = get_tx_gain_range ( ALL_GAINS , chan ) ;
double gain_range_width = gain_range . stop ( ) - gain_range . start ( ) ;
// In case we have a device without a range of gains:
if ( gain_range_width = = 0.0 ) {
return 0.0 ;
}
double norm_gain = ( get_rx_gain ( ALL_GAINS , chan ) - gain_range . start ( ) ) / gain_range_width ;
// Avoid rounding errors:
if ( norm_gain > 1.0 ) return 1.0 ;
if ( norm_gain < 0.0 ) return 0.0 ;
return norm_gain ;
}
2010-10-20 23:20:36 +00:00
gain_range_t get_tx_gain_range ( const std : : string & name , size_t chan ) {
2014-01-30 23:20:49 +00:00
try {
return tx_gain_group ( chan ) - > get_range ( name ) ;
2015-03-11 23:14:00 +00:00
} catch ( uhd : : key_error & ) {
2014-02-22 02:08:56 +00:00
THROW_GAIN_NAME_ERROR ( name , chan , tx ) ;
2014-01-30 23:20:49 +00:00
}
2010-10-17 01:07:10 +00:00
}
2010-10-20 23:20:36 +00:00
std : : vector < std : : string > get_tx_gain_names ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return tx_gain_group ( chan ) - > get_names ( ) ;
2010-10-17 01:07:10 +00:00
}
void set_tx_antenna ( const std : : string & ant , size_t chan ) {
2011-06-29 02:10:55 +00:00
_tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " antenna " / " value " ) . set ( ant ) ;
2010-10-17 01:07:10 +00:00
}
std : : string get_tx_antenna ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
std : : vector < std : : string > get_tx_antennas ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < std : : vector < std : : string > > ( tx_rf_fe_root ( chan ) / " antenna " / " options " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2010-10-19 22:42:21 +00:00
void set_tx_bandwidth ( double bandwidth , size_t chan ) {
2011-06-29 02:10:55 +00:00
_tree - > access < double > ( tx_rf_fe_root ( chan ) / " bandwidth " / " value " ) . set ( bandwidth ) ;
2010-10-19 22:42:21 +00:00
}
double get_tx_bandwidth ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < double > ( tx_rf_fe_root ( chan ) / " bandwidth " / " value " ) . get ( ) ;
2010-10-19 22:42:21 +00:00
}
2011-10-26 17:21:11 +00:00
meta_range_t get_tx_bandwidth_range ( size_t chan ) {
return _tree - > access < meta_range_t > ( tx_rf_fe_root ( chan ) / " bandwidth " / " range " ) . get ( ) ;
}
2010-10-17 01:07:10 +00:00
dboard_iface : : sptr get_tx_dboard_iface ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < dboard_iface : : sptr > ( tx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " iface " ) . get ( ) ;
2010-10-17 01:07:10 +00:00
}
2011-02-12 02:07:24 +00:00
sensor_value_t get_tx_sensor ( const std : : string & name , size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > access < sensor_value_t > ( tx_rf_fe_root ( chan ) / " sensors " / name ) . get ( ) ;
2011-02-12 02:07:24 +00:00
}
std : : vector < std : : string > get_tx_sensor_names ( size_t chan ) {
2011-06-29 02:10:55 +00:00
return _tree - > list ( tx_rf_fe_root ( chan ) / " sensors " ) ;
2011-02-12 02:07:24 +00:00
}
2011-10-21 23:38:27 +00:00
void set_tx_dc_offset ( const std : : complex < double > & offset , size_t chan ) {
if ( chan ! = ALL_CHANS ) {
2014-04-30 12:19:21 +00:00
if ( _tree - > exists ( tx_fe_root ( chan ) / " dc_offset " / " value " ) ) {
_tree - > access < std : : complex < double > > ( tx_fe_root ( chan ) / " dc_offset " / " value " ) . set ( offset ) ;
} else {
UHD_MSG ( warning ) < < " Setting DC offset is not possible on this device. " < < std : : endl ;
}
2011-10-21 23:38:27 +00:00
return ;
}
for ( size_t c = 0 ; c < get_tx_num_channels ( ) ; c + + ) {
this - > set_tx_dc_offset ( offset , c ) ;
}
}
2011-10-24 17:36:41 +00:00
void set_tx_iq_balance ( const std : : complex < double > & offset , size_t chan ) {
2011-10-24 01:02:43 +00:00
if ( chan ! = ALL_CHANS ) {
2014-04-30 12:19:21 +00:00
if ( _tree - > exists ( tx_fe_root ( chan ) / " iq_balance " / " value " ) ) {
_tree - > access < std : : complex < double > > ( tx_fe_root ( chan ) / " iq_balance " / " value " ) . set ( offset ) ;
} else {
UHD_MSG ( warning ) < < " Setting IQ balance is not possible on this device. " < < std : : endl ;
}
2011-10-24 01:02:43 +00:00
return ;
}
for ( size_t c = 0 ; c < get_tx_num_channels ( ) ; c + + ) {
2011-10-24 17:36:41 +00:00
this - > set_tx_iq_balance ( offset , c ) ;
2011-10-24 01:02:43 +00:00
}
}
2014-02-04 19:04:07 +00:00
/*******************************************************************
* GPIO methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
std : : vector < std : : string > get_gpio_banks ( const size_t mboard )
{
std : : vector < std : : string > banks ;
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " ) )
{
BOOST_FOREACH ( const std : : string & name , _tree - > list ( mb_root ( mboard ) / " gpio " ) )
{
banks . push_back ( name ) ;
}
}
BOOST_FOREACH ( const std : : string & name , _tree - > list ( mb_root ( mboard ) / " dboards " ) )
{
banks . push_back ( " RX " + name ) ;
banks . push_back ( " TX " + name ) ;
}
return banks ;
}
2016-10-31 21:30:52 +00:00
void set_gpio_attr ( const std : : string & bank , const std : : string & attr , const uint32_t value , const uint32_t mask , const size_t mboard )
2014-02-04 19:04:07 +00:00
{
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) )
{
2016-10-31 21:30:52 +00:00
const uint32_t current = _tree - > access < uint32_t > ( mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ;
const uint32_t new_value = ( current & ~ mask ) | ( value & mask ) ;
_tree - > access < uint32_t > ( mb_root ( mboard ) / " gpio " / bank / attr ) . set ( new_value ) ;
2014-02-04 19:04:07 +00:00
return ;
}
if ( bank . size ( ) > 2 and bank [ 1 ] = = ' X ' )
{
const std : : string name = bank . substr ( 2 ) ;
const dboard_iface : : unit_t unit = ( bank [ 0 ] = = ' R ' ) ? dboard_iface : : UNIT_RX : dboard_iface : : UNIT_TX ;
dboard_iface : : sptr iface = _tree - > access < dboard_iface : : sptr > ( mb_root ( mboard ) / " dboards " / name / " iface " ) . get ( ) ;
2016-10-31 21:30:52 +00:00
if ( attr = = " CTRL " ) iface - > set_pin_ctrl ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " DDR " ) iface - > set_gpio_ddr ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " OUT " ) iface - > set_gpio_out ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " ATR_0X " ) iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_IDLE , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " ATR_RX " ) iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_RX_ONLY , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " ATR_TX " ) iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_TX_ONLY , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = " ATR_XX " ) iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_FULL_DUPLEX , uint16_t ( value ) , uint16_t ( mask ) ) ;
2014-02-04 19:04:07 +00:00
}
}
2016-10-31 21:30:52 +00:00
uint32_t get_gpio_attr ( const std : : string & bank , const std : : string & attr , const size_t mboard )
2014-02-04 19:04:07 +00:00
{
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) )
{
2016-10-31 21:30:52 +00:00
return uint32_t ( _tree - > access < uint64_t > ( mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ) ;
2014-02-04 19:04:07 +00:00
}
if ( bank . size ( ) > 2 and bank [ 1 ] = = ' X ' )
{
const std : : string name = bank . substr ( 2 ) ;
const dboard_iface : : unit_t unit = ( bank [ 0 ] = = ' R ' ) ? dboard_iface : : UNIT_RX : dboard_iface : : UNIT_TX ;
dboard_iface : : sptr iface = _tree - > access < dboard_iface : : sptr > ( mb_root ( mboard ) / " dboards " / name / " iface " ) . get ( ) ;
if ( attr = = " CTRL " ) return iface - > get_pin_ctrl ( unit ) ;
if ( attr = = " DDR " ) return iface - > get_gpio_ddr ( unit ) ;
if ( attr = = " OUT " ) return iface - > get_gpio_out ( unit ) ;
2015-09-25 01:42:14 +00:00
if ( attr = = " ATR_0X " ) return iface - > get_atr_reg ( unit , gpio_atr : : ATR_REG_IDLE ) ;
if ( attr = = " ATR_RX " ) return iface - > get_atr_reg ( unit , gpio_atr : : ATR_REG_RX_ONLY ) ;
if ( attr = = " ATR_TX " ) return iface - > get_atr_reg ( unit , gpio_atr : : ATR_REG_TX_ONLY ) ;
if ( attr = = " ATR_XX " ) return iface - > get_atr_reg ( unit , gpio_atr : : ATR_REG_FULL_DUPLEX ) ;
2014-02-04 19:04:07 +00:00
if ( attr = = " READBACK " ) return iface - > read_gpio ( unit ) ;
}
return 0 ;
}
2016-10-31 21:30:52 +00:00
void write_register ( const std : : string & path , const uint32_t field , const uint64_t value , const size_t mboard )
2015-08-04 21:09:40 +00:00
{
if ( _tree - > exists ( mb_root ( mboard ) / " registers " ) )
{
uhd : : soft_regmap_accessor_t : : sptr accessor =
_tree - > access < uhd : : soft_regmap_accessor_t : : sptr > ( mb_root ( mboard ) / " registers " ) . get ( ) ;
uhd : : soft_register_base & reg = accessor - > lookup ( path ) ;
2015-08-06 15:23:10 +00:00
if ( not reg . is_writable ( ) ) {
throw uhd : : runtime_error ( " multi_usrp::write_register - register not writable: " + path ) ;
}
2015-08-04 21:09:40 +00:00
switch ( reg . get_bitwidth ( ) ) {
case 16 :
if ( reg . is_readable ( ) )
2016-10-31 21:30:52 +00:00
uhd : : soft_register_base : : cast < uhd : : soft_reg16_rw_t > ( reg ) . write ( field , static_cast < uint16_t > ( value ) ) ;
2015-08-04 21:09:40 +00:00
else
2016-10-31 21:30:52 +00:00
uhd : : soft_register_base : : cast < uhd : : soft_reg16_wo_t > ( reg ) . write ( field , static_cast < uint16_t > ( value ) ) ;
2015-08-04 21:09:40 +00:00
break ;
case 32 :
if ( reg . is_readable ( ) )
2016-10-31 21:30:52 +00:00
uhd : : soft_register_base : : cast < uhd : : soft_reg32_rw_t > ( reg ) . write ( field , static_cast < uint32_t > ( value ) ) ;
2015-08-04 21:09:40 +00:00
else
2016-10-31 21:30:52 +00:00
uhd : : soft_register_base : : cast < uhd : : soft_reg32_wo_t > ( reg ) . write ( field , static_cast < uint32_t > ( value ) ) ;
2015-08-04 21:09:40 +00:00
break ;
case 64 :
if ( reg . is_readable ( ) )
uhd : : soft_register_base : : cast < uhd : : soft_reg64_rw_t > ( reg ) . write ( field , value ) ;
else
uhd : : soft_register_base : : cast < uhd : : soft_reg64_wo_t > ( reg ) . write ( field , value ) ;
break ;
default :
2015-08-06 15:23:10 +00:00
throw uhd : : assertion_error ( " multi_usrp::write_register - register has invalid bitwidth " ) ;
2015-08-04 21:09:40 +00:00
}
} else {
2015-08-06 15:23:10 +00:00
throw uhd : : not_implemented_error ( " multi_usrp::write_register - register IO not supported for this device " ) ;
2015-08-04 21:09:40 +00:00
}
}
2016-10-31 21:30:52 +00:00
uint64_t read_register ( const std : : string & path , const uint32_t field , const size_t mboard )
2015-08-04 21:09:40 +00:00
{
if ( _tree - > exists ( mb_root ( mboard ) / " registers " ) )
{
uhd : : soft_regmap_accessor_t : : sptr accessor =
_tree - > access < uhd : : soft_regmap_accessor_t : : sptr > ( mb_root ( mboard ) / " registers " ) . get ( ) ;
uhd : : soft_register_base & reg = accessor - > lookup ( path ) ;
2015-08-06 15:23:10 +00:00
if ( not reg . is_readable ( ) ) {
throw uhd : : runtime_error ( " multi_usrp::read_register - register not readable: " + path ) ;
}
2015-08-04 21:09:40 +00:00
switch ( reg . get_bitwidth ( ) ) {
case 16 :
if ( reg . is_writable ( ) )
2016-10-31 21:30:52 +00:00
return static_cast < uint64_t > ( uhd : : soft_register_base : : cast < uhd : : soft_reg16_rw_t > ( reg ) . read ( field ) ) ;
2015-08-04 21:09:40 +00:00
else
2016-10-31 21:30:52 +00:00
return static_cast < uint64_t > ( uhd : : soft_register_base : : cast < uhd : : soft_reg16_ro_t > ( reg ) . read ( field ) ) ;
2015-08-04 21:09:40 +00:00
break ;
case 32 :
if ( reg . is_writable ( ) )
2016-10-31 21:30:52 +00:00
return static_cast < uint64_t > ( uhd : : soft_register_base : : cast < uhd : : soft_reg32_rw_t > ( reg ) . read ( field ) ) ;
2015-08-04 21:09:40 +00:00
else
2016-10-31 21:30:52 +00:00
return static_cast < uint64_t > ( uhd : : soft_register_base : : cast < uhd : : soft_reg32_ro_t > ( reg ) . read ( field ) ) ;
2015-08-04 21:09:40 +00:00
break ;
case 64 :
if ( reg . is_writable ( ) )
return uhd : : soft_register_base : : cast < uhd : : soft_reg64_rw_t > ( reg ) . read ( field ) ;
else
return uhd : : soft_register_base : : cast < uhd : : soft_reg64_ro_t > ( reg ) . read ( field ) ;
break ;
default :
2015-08-06 15:23:10 +00:00
throw uhd : : assertion_error ( " multi_usrp::read_register - register has invalid bitwidth: " + path ) ;
2015-08-04 21:09:40 +00:00
}
}
2016-08-11 06:18:32 +00:00
throw uhd : : not_implemented_error ( " multi_usrp::read_register - register IO not supported for this device " ) ;
2015-08-04 21:09:40 +00:00
}
std : : vector < std : : string > enumerate_registers ( const size_t mboard )
{
if ( _tree - > exists ( mb_root ( mboard ) / " registers " ) )
{
uhd : : soft_regmap_accessor_t : : sptr accessor =
_tree - > access < uhd : : soft_regmap_accessor_t : : sptr > ( mb_root ( mboard ) / " registers " ) . get ( ) ;
return accessor - > enumerate ( ) ;
} else {
return std : : vector < std : : string > ( ) ;
}
}
2015-08-06 15:23:10 +00:00
register_info_t get_register_info ( const std : : string & path , const size_t mboard = 0 )
{
if ( _tree - > exists ( mb_root ( mboard ) / " registers " ) )
{
uhd : : soft_regmap_accessor_t : : sptr accessor =
_tree - > access < uhd : : soft_regmap_accessor_t : : sptr > ( mb_root ( mboard ) / " registers " ) . get ( ) ;
uhd : : soft_register_base & reg = accessor - > lookup ( path ) ;
register_info_t info ;
info . bitwidth = reg . get_bitwidth ( ) ;
info . readable = reg . is_readable ( ) ;
info . writable = reg . is_writable ( ) ;
return info ;
} else {
throw uhd : : not_implemented_error ( " multi_usrp::read_register - register IO not supported for this device " ) ;
}
}
2010-10-17 01:07:10 +00:00
private :
device : : sptr _dev ;
2011-06-29 02:10:55 +00:00
property_tree : : sptr _tree ;
2016-08-02 01:17:41 +00:00
bool _is_device3 ;
uhd : : rfnoc : : legacy_compat : : sptr _legacy_compat ;
2010-10-19 01:24:53 +00:00
2011-02-18 07:06:48 +00:00
struct mboard_chan_pair {
size_t mboard , chan ;
mboard_chan_pair ( void ) : mboard ( 0 ) , chan ( 0 ) { }
} ;
mboard_chan_pair rx_chan_to_mcp ( size_t chan ) {
mboard_chan_pair mcp ;
mcp . chan = chan ;
for ( mcp . mboard = 0 ; mcp . mboard < get_num_mboards ( ) ; mcp . mboard + + ) {
size_t sss = get_rx_subdev_spec ( mcp . mboard ) . size ( ) ;
if ( mcp . chan < sss ) break ;
mcp . chan - = sss ;
2010-10-19 20:04:07 +00:00
}
2013-07-15 22:48:51 +00:00
if ( mcp . mboard > = get_num_mboards ( ) )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp: RX channel %u out of range for configured RX frontends " ) % chan ) ) ;
}
2011-02-18 07:06:48 +00:00
return mcp ;
2010-10-19 01:24:53 +00:00
}
2011-02-18 07:06:48 +00:00
mboard_chan_pair tx_chan_to_mcp ( size_t chan ) {
mboard_chan_pair mcp ;
mcp . chan = chan ;
for ( mcp . mboard = 0 ; mcp . mboard < get_num_mboards ( ) ; mcp . mboard + + ) {
size_t sss = get_tx_subdev_spec ( mcp . mboard ) . size ( ) ;
if ( mcp . chan < sss ) break ;
mcp . chan - = sss ;
2010-10-19 20:04:07 +00:00
}
2013-07-15 22:48:51 +00:00
if ( mcp . mboard > = get_num_mboards ( ) )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp: TX channel %u out of range for configured TX frontends " ) % chan ) ) ;
}
2011-02-18 07:06:48 +00:00
return mcp ;
2010-10-19 01:24:53 +00:00
}
2013-07-15 22:48:51 +00:00
fs_path mb_root ( const size_t mboard )
{
try
{
const std : : string name = _tree - > list ( " /mboards " ) . at ( mboard ) ;
return " /mboards/ " + name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::mb_root(%u) - %s " ) % mboard % e . what ( ) ) ) ;
}
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
2013-07-15 22:48:51 +00:00
fs_path rx_dsp_root ( const size_t chan )
{
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > rx_dsp_root ( mcp . mboard , mcp . chan ) ;
}
2014-02-21 14:12:44 +00:00
if ( _tree - > exists ( mb_root ( mcp . mboard ) / " rx_chan_dsp_mapping " ) ) {
std : : vector < size_t > map = _tree - > access < std : : vector < size_t > > ( mb_root ( mcp . mboard ) / " rx_chan_dsp_mapping " ) . get ( ) ;
2014-03-13 16:38:16 +00:00
UHD_ASSERT_THROW ( map . size ( ) > mcp . chan ) ;
2014-02-21 14:12:44 +00:00
mcp . chan = map [ mcp . chan ] ;
}
2013-07-15 22:48:51 +00:00
try
{
const std : : string name = _tree - > list ( mb_root ( mcp . mboard ) / " rx_dsps " ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " rx_dsps " / name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::rx_dsp_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
2013-07-15 22:48:51 +00:00
fs_path tx_dsp_root ( const size_t chan )
{
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = tx_chan_to_mcp ( chan ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > tx_dsp_root ( mcp . mboard , mcp . chan ) ;
}
2014-02-21 14:12:44 +00:00
if ( _tree - > exists ( mb_root ( mcp . mboard ) / " tx_chan_dsp_mapping " ) ) {
std : : vector < size_t > map = _tree - > access < std : : vector < size_t > > ( mb_root ( mcp . mboard ) / " tx_chan_dsp_mapping " ) . get ( ) ;
2014-03-13 16:38:16 +00:00
UHD_ASSERT_THROW ( map . size ( ) > mcp . chan ) ;
2014-02-21 14:12:44 +00:00
mcp . chan = map [ mcp . chan ] ;
}
2013-07-15 22:48:51 +00:00
try
{
const std : : string name = _tree - > list ( mb_root ( mcp . mboard ) / " tx_dsps " ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " tx_dsps " / name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::tx_dsp_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
2013-07-15 22:48:51 +00:00
fs_path rx_fe_root ( const size_t chan )
{
2011-10-26 02:26:11 +00:00
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > rx_fe_root ( mcp . mboard , mcp . chan ) ;
}
2013-07-15 22:48:51 +00:00
try
{
const subdev_spec_pair_t spec = get_rx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " rx_frontends " / spec . db_name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::rx_fe_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2011-10-26 02:26:11 +00:00
}
2013-07-15 22:48:51 +00:00
fs_path tx_fe_root ( const size_t chan )
{
2011-10-26 02:26:11 +00:00
mboard_chan_pair mcp = tx_chan_to_mcp ( chan ) ;
2016-08-02 01:17:41 +00:00
if ( is_device3 ( ) ) {
return _legacy_compat - > tx_fe_root ( mcp . mboard , mcp . chan ) ;
}
2013-07-15 22:48:51 +00:00
try
{
const subdev_spec_pair_t spec = get_tx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " tx_frontends " / spec . db_name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::tx_fe_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2011-10-26 02:26:11 +00:00
}
2013-07-15 22:48:51 +00:00
fs_path rx_rf_fe_root ( const size_t chan )
{
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
2013-07-15 22:48:51 +00:00
try
{
const subdev_spec_pair_t spec = get_rx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " dboards " / spec . db_name / " rx_frontends " / spec . sd_name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::rx_rf_fe_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
2013-07-15 22:48:51 +00:00
fs_path tx_rf_fe_root ( const size_t chan )
{
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = tx_chan_to_mcp ( chan ) ;
2013-07-15 22:48:51 +00:00
try
{
const subdev_spec_pair_t spec = get_tx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
return mb_root ( mcp . mboard ) / " dboards " / spec . db_name / " tx_frontends " / spec . sd_name ;
}
catch ( const std : : exception & e )
{
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::tx_rf_fe_root(%u) - mcp(%u) - %s " ) % chan % mcp . chan % e . what ( ) ) ) ;
}
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
gain_group : : sptr rx_gain_group ( size_t chan ) {
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = rx_chan_to_mcp ( chan ) ;
2011-06-29 02:10:55 +00:00
const subdev_spec_pair_t spec = get_rx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
gain_group : : sptr gg = gain_group : : make ( ) ;
BOOST_FOREACH ( const std : : string & name , _tree - > list ( mb_root ( mcp . mboard ) / " rx_codecs " / spec . db_name / " gains " ) ) {
2011-07-08 17:08:43 +00:00
gg - > register_fcns ( " ADC- " + name , make_gain_fcns_from_subtree ( _tree - > subtree ( mb_root ( mcp . mboard ) / " rx_codecs " / spec . db_name / " gains " / name ) ) , 0 /* low prio */ ) ;
2011-06-29 02:10:55 +00:00
}
BOOST_FOREACH ( const std : : string & name , _tree - > list ( rx_rf_fe_root ( chan ) / " gains " ) ) {
2011-07-08 17:08:43 +00:00
gg - > register_fcns ( name , make_gain_fcns_from_subtree ( _tree - > subtree ( rx_rf_fe_root ( chan ) / " gains " / name ) ) , 1 /* high prio */ ) ;
2011-06-29 02:10:55 +00:00
}
return gg ;
2010-10-17 01:07:10 +00:00
}
2011-06-29 02:10:55 +00:00
gain_group : : sptr tx_gain_group ( size_t chan ) {
2011-02-18 07:06:48 +00:00
mboard_chan_pair mcp = tx_chan_to_mcp ( chan ) ;
2011-06-29 02:10:55 +00:00
const subdev_spec_pair_t spec = get_tx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
gain_group : : sptr gg = gain_group : : make ( ) ;
BOOST_FOREACH ( const std : : string & name , _tree - > list ( mb_root ( mcp . mboard ) / " tx_codecs " / spec . db_name / " gains " ) ) {
2012-09-13 01:24:28 +00:00
gg - > register_fcns ( " DAC- " + name , make_gain_fcns_from_subtree ( _tree - > subtree ( mb_root ( mcp . mboard ) / " tx_codecs " / spec . db_name / " gains " / name ) ) , 1 /* high prio */ ) ;
2011-06-29 02:10:55 +00:00
}
BOOST_FOREACH ( const std : : string & name , _tree - > list ( tx_rf_fe_root ( chan ) / " gains " ) ) {
2011-07-08 17:08:43 +00:00
gg - > register_fcns ( name , make_gain_fcns_from_subtree ( _tree - > subtree ( tx_rf_fe_root ( chan ) / " gains " / name ) ) , 0 /* low prio */ ) ;
2011-06-29 02:10:55 +00:00
}
return gg ;
2010-10-17 01:07:10 +00:00
}
2014-02-28 17:14:31 +00:00
//! \param is_tx True for tx
// Assumption is that all mboards use the same link
2016-06-06 20:45:31 +00:00
// and that the rate sum is evenly distributed among the mboards
2014-02-28 17:14:31 +00:00
bool _check_link_rate ( const stream_args_t & args , bool is_tx ) {
bool link_rate_is_ok = true ;
2014-04-15 15:50:42 +00:00
size_t bytes_per_sample = convert : : get_bytes_per_item ( args . otw_format . empty ( ) ? " sc16 " : args . otw_format ) ;
2014-02-28 17:14:31 +00:00
double max_link_rate = 0 ;
double sum_rate = 0 ;
BOOST_FOREACH ( const size_t chan , args . channels ) {
mboard_chan_pair mcp = is_tx ? tx_chan_to_mcp ( chan ) : rx_chan_to_mcp ( chan ) ;
if ( _tree - > exists ( mb_root ( mcp . mboard ) / " link_max_rate " ) ) {
max_link_rate = std : : max (
max_link_rate ,
_tree - > access < double > ( mb_root ( mcp . mboard ) / " link_max_rate " ) . get ( )
) ;
}
sum_rate + = is_tx ? get_tx_rate ( chan ) : get_rx_rate ( chan ) ;
}
2016-06-06 20:45:31 +00:00
sum_rate / = get_num_mboards ( ) ;
2014-02-28 17:14:31 +00:00
if ( max_link_rate > 0 and ( max_link_rate / bytes_per_sample ) < sum_rate ) {
UHD_MSG ( warning ) < < boost : : format (
" The total sum of rates (%f MSps on %u channels) exceeds the maximum capacity of the connection. \n "
" This can cause %s. "
) % ( sum_rate / 1e6 ) % args . channels . size ( ) % ( is_tx ? " underruns (U) " : " overflows (O) " ) < < std : : endl ;
link_rate_is_ok = false ;
}
return link_rate_is_ok ;
}
2010-10-17 01:07:10 +00:00
} ;
2014-08-13 15:44:31 +00:00
multi_usrp : : ~ multi_usrp ( void ) {
/* NOP */
}
2010-10-17 01:07:10 +00:00
/***********************************************************************
* The Make Function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
multi_usrp : : sptr multi_usrp : : make ( const device_addr_t & dev_addr ) {
2013-07-15 22:48:51 +00:00
UHD_LOG < < " multi_usrp::make with args " < < dev_addr . to_pp_string ( ) < < std : : endl ;
2010-10-17 01:07:10 +00:00
return sptr ( new multi_usrp_impl ( dev_addr ) ) ;
}