2010-10-17 01:07:10 +00:00
//
2016-08-02 01:17:41 +00:00
// Copyright 2010-2016 Ettus Research LLC
2018-02-19 23:30:32 +00:00
// Copyright 2018 Ettus Research, a National Instruments Company
2010-10-17 01:07:10 +00:00
//
2018-02-19 23:30:32 +00:00
// SPDX-License-Identifier: GPL-3.0-or-later
2010-10-17 01:07:10 +00:00
//
2011-06-29 02:10:55 +00:00
# include <uhd/property_tree.hpp>
2018-04-02 21:57:26 +00:00
# include <uhd/types/eeprom.hpp>
2010-10-17 01:07:10 +00:00
# include <uhd/usrp/multi_usrp.hpp>
2018-02-21 21:28:50 +00:00
# include <uhd/usrp/gpio_defs.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>
2018-02-23 22:30:40 +00:00
# include <uhdlib/usrp/gpio_defs.hpp>
2018-01-31 19:20:14 +00:00
# include <uhdlib/rfnoc/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/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>
2018-02-21 21:28:50 +00:00
# include <bitset>
2018-04-26 16:30:48 +00:00
# include <chrono>
# include <thread>
2010-10-17 01:07:10 +00:00
using namespace uhd ;
using namespace uhd : : usrp ;
2018-10-03 21:48:03 +00:00
const size_t multi_usrp : : ALL_MBOARDS = size_t ( ~ 0 ) ;
const size_t multi_usrp : : ALL_CHANS = size_t ( ~ 0 ) ;
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 ) {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < 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 ) {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " ) < < boost : : format (
2014-08-05 21:05:09 +00:00
" 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 ( ) ;
2017-02-08 00:37:25 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " ) < < results_string ;
2014-08-05 21:05:09 +00:00
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 ( ) ;
}
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < results_string ;
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 ;
2017-02-10 07:19:55 +00:00
for ( const range_t & sub_range : fe_range ) {
2011-08-29 16:43:54 +00:00
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 ;
2017-05-15 20:55:09 +00:00
if ( rf_fe_subtree - > exists ( " use_lo_offset " ) and
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 ) ) ;
2018-08-24 00:07:00 +00:00
if ( is_device3 ( ) and not addr . has_key ( " recover_mb_eeprom " ) ) {
2016-08-02 01:17:41 +00:00
_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 ;
2018-04-02 21:57:26 +00:00
const auto mb_eeprom =
_tree - > access < mboard_eeprom_t > ( mb_root ( mcp . mboard ) / " eeprom " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_id " ] = _tree - > access < std : : string > ( mb_root ( mcp . mboard ) / " name " ) . get ( ) ;
2018-04-02 21:57:26 +00:00
usrp_info [ " mboard_name " ] = mb_eeprom . get ( " name " , " n/a " ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_serial " ] = mb_eeprom [ " serial " ] ;
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 ( ) ;
2014-12-19 02:45:48 +00:00
usrp_info [ " rx_antenna " ] = _tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2018-04-02 21:57:26 +00:00
if ( _tree - > exists ( rx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " rx_eeprom " ) ) {
const auto db_eeprom =
_tree - > access < dboard_eeprom_t > (
rx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( )
/ " rx_eeprom "
) . get ( ) ;
usrp_info [ " rx_serial " ] = db_eeprom . serial ;
usrp_info [ " rx_id " ] = db_eeprom . id . to_pp_string ( ) ;
}
const auto rfnoc_path = mb_root ( mcp . mboard ) / " xbar " ;
if ( _tree - > exists ( rfnoc_path ) ) {
const auto spec = get_rx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
const auto radio_index = get_radio_index ( spec . db_name ) ;
const auto radio_path = rfnoc_path / str ( boost : : format ( " Radio_%d " ) % radio_index ) ;
const auto eeprom_path = radio_path / " eeprom " ;
2018-05-14 19:51:19 +00:00
if ( _tree - > exists ( eeprom_path ) ) {
2018-04-02 21:57:26 +00:00
const auto db_eeprom = _tree - > access < eeprom_map_t > ( eeprom_path ) . get ( ) ;
usrp_info [ " rx_serial " ] = db_eeprom . count ( " serial " ) ?
std : : string ( db_eeprom . at ( " serial " ) . begin ( ) , db_eeprom . at ( " serial " ) . end ( ) )
: " n/a "
;
usrp_info [ " rx_id " ] = db_eeprom . count ( " pid " ) ?
std : : string ( db_eeprom . at ( " pid " ) . begin ( ) , db_eeprom . at ( " pid " ) . end ( ) )
: " n/a "
;
}
}
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 ;
2018-04-02 21:57:26 +00:00
const auto mb_eeprom =
_tree - > access < mboard_eeprom_t > ( mb_root ( mcp . mboard ) / " eeprom " ) . get ( ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_id " ] = _tree - > access < std : : string > ( mb_root ( mcp . mboard ) / " name " ) . get ( ) ;
2018-07-17 16:04:02 +00:00
usrp_info [ " mboard_name " ] = mb_eeprom . get ( " name " , " n/a " ) ;
2012-04-05 00:03:35 +00:00
usrp_info [ " mboard_serial " ] = mb_eeprom [ " serial " ] ;
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 ( ) ;
2014-12-19 02:45:48 +00:00
usrp_info [ " tx_antenna " ] = _tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " antenna " / " value " ) . get ( ) ;
2018-04-02 21:57:26 +00:00
if ( _tree - > exists ( tx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( ) / " tx_eeprom " ) ) {
const auto db_eeprom =
_tree - > access < dboard_eeprom_t > (
tx_rf_fe_root ( chan ) . branch_path ( ) . branch_path ( )
/ " tx_eeprom "
) . get ( ) ;
usrp_info [ " tx_serial " ] = db_eeprom . serial ;
usrp_info [ " tx_id " ] = db_eeprom . id . to_pp_string ( ) ;
}
const auto rfnoc_path = mb_root ( mcp . mboard ) / " xbar " ;
if ( _tree - > exists ( rfnoc_path ) ) {
const auto spec = get_tx_subdev_spec ( mcp . mboard ) . at ( mcp . chan ) ;
const auto radio_index = get_radio_index ( spec . db_name ) ;
const auto radio_path = rfnoc_path / str ( boost : : format ( " Radio_%d " ) % radio_index ) ;
const auto path = radio_path / " eeprom " ;
2018-05-14 19:51:19 +00:00
if ( _tree - > exists ( path ) ) {
2018-04-02 21:57:26 +00:00
const auto db_eeprom = _tree - > access < eeprom_map_t > ( path ) . get ( ) ;
usrp_info [ " tx_serial " ] = db_eeprom . count ( " serial " ) ?
std : : string ( db_eeprom . at ( " serial " ) . begin ( ) , db_eeprom . at ( " serial " ) . end ( ) )
: " n/a "
;
usrp_info [ " tx_id " ] = db_eeprom . count ( " pid " ) ?
std : : string ( db_eeprom . at ( " pid " ) . begin ( ) , db_eeprom . at ( " pid " ) . end ( ) )
: " n/a "
;
}
}
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 ) ;
2017-02-08 00:37:25 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " ) < < " Setting master clock rate selection to 'manual'. " ;
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
}
2018-03-28 21:39:30 +00:00
meta_range_t get_master_clock_rate_range ( const size_t mboard )
{
if ( _tree - > exists ( mb_root ( mboard ) / " tick_rate/range " ) ) {
return _tree - > access < meta_range_t > (
mb_root ( mboard ) / " tick_rate/range "
) . get ( ) ;
}
// The USRP may not have a range defined, in which case we create a
// fake range with a single value:
const double tick_rate = get_master_clock_rate ( mboard ) ;
return meta_range_t (
tick_rate ,
tick_rate ,
0
) ;
}
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 ) {
2018-05-09 23:56:35 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " )
< < " 1) catch time transition at pps edge " ;
auto end_time = std : : chrono : : steady_clock : : now ( )
+ std : : chrono : : 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 ( ) )
{
2018-05-09 23:56:35 +00:00
if ( std : : chrono : : steady_clock : : now ( ) > 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
) ;
}
2018-04-26 16:30:48 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ;
2010-10-17 01:07:10 +00:00
}
2018-05-09 23:56:35 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " )
< < " 2) set times next pps (synchronously) " ;
2011-12-12 20:49:40 +00:00
set_time_next_pps ( time_spec , ALL_MBOARDS ) ;
2018-04-26 16:30:48 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
2010-10-17 01:07:10 +00:00
//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
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < 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 ) {
2018-07-30 23:52:54 +00:00
const auto time_source_path =
mb_root ( mboard ) / " time_source/value " ;
const auto sync_source_path =
mb_root ( mboard ) / " sync_source/value " ;
if ( _tree - > exists ( time_source_path ) ) {
_tree - > access < std : : string > ( time_source_path ) . set ( source ) ;
} else if ( _tree - > exists ( sync_source_path ) ) {
auto sync_source =
_tree - > access < device_addr_t > ( sync_source_path ) . get ( ) ;
sync_source [ " time_source " ] = source ;
_tree - > access < device_addr_t > ( sync_source_path ) . set ( sync_source ) ;
} else {
throw uhd : : runtime_error ( " Can't set time source on this device. " ) ;
}
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 ) {
2018-07-30 23:52:54 +00:00
const auto time_source_path = mb_root ( mboard ) / " time_source/value " ;
if ( _tree - > exists ( time_source_path ) ) {
return _tree - > access < std : : string > ( time_source_path ) . get ( ) ;
} else if ( _tree - > exists ( mb_root ( mboard ) / " sync_source/value " ) ) {
auto sync_source = _tree - > access < device_addr_t > (
mb_root ( mboard ) / " sync_source " / " value " ) . get ( ) ;
if ( sync_source . has_key ( " time_source " ) ) {
return sync_source . get ( " time_source " ) ;
}
}
throw uhd : : runtime_error ( " Cannot query time_source on this device! " ) ;
2011-10-12 16:59:41 +00:00
}
std : : vector < std : : string > get_time_sources ( const size_t mboard ) {
2018-07-30 23:52:54 +00:00
const auto time_source_path = mb_root ( mboard ) / " time_source/options " ;
if ( _tree - > exists ( time_source_path ) ) {
return _tree - > access < std : : vector < std : : string > > ( time_source_path )
. get ( ) ;
} else if ( _tree - > exists ( mb_root ( mboard ) / " sync_source/options " ) ) {
const auto sync_sources = get_sync_sources ( mboard ) ;
std : : vector < std : : string > time_sources ;
for ( const auto & sync_source : sync_sources ) {
if ( sync_source . has_key ( " time_source " ) ) {
time_sources . push_back ( sync_source . get ( " time_source " ) ) ;
}
}
}
throw uhd : : runtime_error ( " Cannot query time_source on this device! " ) ;
2011-10-12 16:59:41 +00:00
}
void set_clock_source ( const std : : string & source , const size_t mboard ) {
if ( mboard ! = ALL_MBOARDS ) {
2018-07-30 23:52:54 +00:00
const auto clock_source_path =
mb_root ( mboard ) / " clock_source/value " ;
const auto sync_source_path =
mb_root ( mboard ) / " sync_source/value " ;
if ( _tree - > exists ( clock_source_path ) ) {
_tree - > access < std : : string > ( clock_source_path ) . set ( source ) ;
} else if ( _tree - > exists ( sync_source_path ) ) {
auto sync_source =
_tree - > access < device_addr_t > ( sync_source_path ) . get ( ) ;
sync_source [ " clock_source " ] = source ;
_tree - > access < device_addr_t > ( sync_source_path ) . set ( sync_source ) ;
} else {
throw uhd : : runtime_error (
" Can't set clock source on this device. " ) ;
}
2011-10-12 16:59:41 +00:00
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 ) {
2018-07-30 23:52:54 +00:00
const auto clock_source_path = mb_root ( mboard ) / " clock_source/value " ;
if ( _tree - > exists ( clock_source_path ) ) {
return _tree - > access < std : : string > (
mb_root ( mboard ) / " clock_source " / " value " ) . get ( ) ;
} else if ( _tree - > exists ( mb_root ( mboard ) / " sync_source/value " ) ) {
auto sync_source = _tree - > access < device_addr_t > (
mb_root ( mboard ) / " sync_source " / " value " ) . get ( ) ;
if ( sync_source . has_key ( " clock_source " ) ) {
return sync_source . get ( " clock_source " ) ;
}
}
throw uhd : : runtime_error ( " Cannot query clock_source on this device! " ) ;
}
void set_sync_source (
const std : : string & clock_source ,
const std : : string & time_source ,
const size_t mboard
) {
device_addr_t sync_args ;
sync_args [ " clock_source " ] = clock_source ;
sync_args [ " time_source " ] = time_source ;
set_sync_source ( sync_args , mboard ) ;
}
void set_sync_source (
const device_addr_t & sync_source ,
const size_t mboard
) {
if ( mboard ! = ALL_MBOARDS ) {
const auto sync_source_path =
mb_root ( mboard ) / " sync_source/value " ;
if ( _tree - > exists ( sync_source_path ) ) {
_tree - > access < device_addr_t > ( sync_source_path )
. set ( sync_source ) ;
} else if ( _tree - > exists ( mb_root ( mboard ) / " clock_source/value " )
and _tree - > exists ( mb_root ( mboard ) / " time_source/value " )
and sync_source . has_key ( " clock_source " )
and sync_source . has_key ( " time_source " ) ) {
const std : : string clock_source = sync_source [ " clock_source " ] ;
const std : : string time_source = sync_source [ " time_source " ] ;
set_clock_source ( clock_source , mboard ) ;
set_time_source ( time_source , mboard ) ;
} else {
throw uhd : : runtime_error (
" Can't set sync source on this device. " ) ;
}
return ;
}
for ( size_t m = 0 ; m < get_num_mboards ( ) ; m + + ) {
this - > set_sync_source ( sync_source , m ) ;
}
}
device_addr_t get_sync_source ( const size_t mboard )
{
const auto sync_source_path = mb_root ( mboard ) / " sync_source/value " ;
if ( _tree - > exists ( sync_source_path ) ) {
return _tree - > access < device_addr_t > ( sync_source_path ) . get ( ) ;
}
// If this path is not there, we fall back to the oldschool method and
// convert to a new-fangled sync source dictionary
const std : : string clock_source = get_clock_source ( mboard ) ;
const std : : string time_source = get_time_source ( mboard ) ;
device_addr_t sync_source ;
sync_source [ " clock_source " ] = clock_source ;
sync_source [ " time_source " ] = time_source ;
return sync_source ;
}
std : : vector < device_addr_t > get_sync_sources ( const size_t mboard )
{
const auto sync_source_path = mb_root ( mboard ) / " sync_source/options " ;
if ( _tree - > exists ( sync_source_path ) ) {
return _tree - > access < std : : vector < device_addr_t > > ( sync_source_path ) . get ( ) ;
}
// If this path is not there, we fall back to the oldschool method and
// convert to a new-fangled sync source dictionary
const auto clock_sources = get_clock_sources ( mboard ) ;
const auto time_sources = get_time_sources ( mboard ) ;
std : : vector < device_addr_t > sync_sources ;
for ( const auto & clock_source : clock_sources ) {
for ( const auto & time_source : time_sources ) {
device_addr_t sync_source ;
sync_source [ " clock_source " ] = clock_source ;
sync_source [ " time_source " ] = time_source ;
sync_sources . push_back ( sync_source ) ;
}
}
return sync_sources ;
2011-10-12 16:59:41 +00:00
}
std : : vector < std : : string > get_clock_sources ( const size_t mboard ) {
2018-07-30 23:52:54 +00:00
const auto clock_source_path = mb_root ( mboard ) / " clock_source/options " ;
if ( _tree - > exists ( clock_source_path ) ) {
return _tree - > access < std : : vector < std : : string > > ( clock_source_path )
. get ( ) ;
} else if ( _tree - > exists ( mb_root ( mboard ) / " sync_source/options " ) ) {
const auto sync_sources = get_sync_sources ( mboard ) ;
std : : vector < std : : string > clock_sources ;
for ( const auto & sync_source : sync_sources ) {
if ( sync_source . has_key ( " clock_source " ) ) {
clock_sources . push_back ( sync_source . get ( " clock_source " ) ) ;
}
}
}
throw uhd : : runtime_error ( " Cannot query clock_source on this device! " ) ;
2011-10-12 16:59:41 +00:00
}
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 ) {
2018-05-17 21:43:12 +00:00
if ( _tree - > exists ( mb_root ( mboard ) / " sensors " ) ) {
return _tree - > list ( mb_root ( mboard ) / " sensors " ) ;
}
return { } ;
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 ) ;
}
}
2018-08-09 22:16:01 +00:00
wb_iface : : sptr get_user_settings_iface ( const size_t chan )
{
const auto user_settings_path =
rx_rf_fe_root ( chan ) / " user_settings " / " iface " ;
if ( _tree - > exists ( user_settings_path ) ) {
return _tree - > access < wb_iface : : sptr > ( user_settings_path ) . get ( ) ;
}
UHD_LOG_WARNING ( " MULTI_USRP " ,
" Attempting to read back non-existant user settings iface! " ) ;
return nullptr ;
}
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 ( ) ) ) ;
}
2017-02-08 00:37:25 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " ) < < " Selecting default RX front end spec: " < < spec . to_pp_string ( ) ;
2013-07-15 22:48:51 +00:00
}
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 ) {
2018-07-10 09:25:54 +00:00
// If any mixer is driven by an external LO the daughterboard assumes that no CORDIC correction is
// necessary. Since the LO might be sourced from another daughterboard which would normally apply a
// cordic correction a manual DSP tune policy should be used to ensure identical configurations across
// daughterboards.
if ( tune_request . dsp_freq_policy = = tune_request . POLICY_AUTO and
tune_request . rf_freq_policy = = tune_request . POLICY_AUTO )
{
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
2018-07-17 23:48:49 +00:00
const bool external_all_los = _tree - > exists ( rx_rf_fe_root ( chan ) / " los " / ALL_LOS )
& & get_rx_lo_source ( ALL_LOS , c ) = = " external " ;
if ( external_all_los ) {
2018-07-10 09:25:54 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " )
< < " At least one channel is using an external LO. "
< < " Using a manual DSP frequency policy is recommended to ensure "
< < " the same frequency shift on all channels. " ;
break ;
}
}
}
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 ( ) ;
}
2017-12-05 19:17:03 +00:00
/**************************************************************************
* LO controls
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 " ) ) {
2017-02-10 07:19:55 +00:00
for ( const std : : string & name : _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
2016-07-19 16:27:38 +00:00
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 {
2017-02-10 07:19:55 +00:00
for ( const std : : string & n : _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
2016-07-19 16:27:38 +00:00
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 {
2017-02-10 07:19:55 +00:00
for ( const std : : string & n : _tree - > list ( rx_rf_fe_root ( chan ) / " los " ) ) {
2016-07-19 16:27:38 +00:00
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
}
}
2017-12-05 19:17:03 +00:00
std : : vector < std : : string > get_tx_lo_names ( const size_t chan = 0 ) {
std : : vector < std : : string > lo_names ;
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
for ( const std : : string & name : _tree - > list ( tx_rf_fe_root ( chan ) / " los " ) ) {
lo_names . push_back ( name ) ;
}
}
return lo_names ;
}
void set_tx_lo_source (
const std : : string & src ,
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " / ALL_LOS ) ) {
// Special value ALL_LOS support atomically sets the source
// for all LOs
_tree - > access < std : : string > (
tx_rf_fe_root ( chan ) / " los " / ALL_LOS /
" source " / " value "
) . set ( src ) ;
} else {
for ( const auto & n : _tree - > list ( tx_rf_fe_root ( chan ) / " los " ) ) {
this - > set_tx_lo_source ( src , n , chan ) ;
}
}
} else {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
_tree - > access < std : : string > (
tx_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_tx_lo_source (
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < std : : string > (
tx_rf_fe_root ( chan ) / " los " / name / " source " / " value "
) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
} else {
// If the daughterboard doesn't expose its LO(s) then it can only
// be internal
return " internal " ;
}
}
std : : vector < std : : string > get_tx_lo_sources (
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( tx_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 > > (
tx_rf_fe_root ( chan ) / " los " / ALL_LOS /
" source " / " options "
) . get ( ) ;
} else {
return std : : vector < std : : string > ( ) ;
}
} else {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < std : : vector < std : : string > > ( tx_rf_fe_root ( chan ) / " los " / name / " source " / " options " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
// If the daughterboard doesn't expose its LO(s) then it can only
// be internal
return std : : vector < std : : string > ( 1 , " internal " ) ;
}
}
void set_tx_lo_export_enabled (
const bool enabled ,
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
if ( name = = ALL_LOS ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " / ALL_LOS ) ) {
//Special value ALL_LOS support atomically sets the source for all LOs
_tree - > access < bool > ( tx_rf_fe_root ( chan ) / " los " / ALL_LOS / " export " ) . set ( enabled ) ;
} else {
for ( const std : : string & n : _tree - > list ( tx_rf_fe_root ( chan ) / " los " ) ) {
this - > set_tx_lo_export_enabled ( enabled , n , chan ) ;
}
}
} else {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
_tree - > access < bool > ( tx_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_tx_lo_export_enabled (
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < bool > (
tx_rf_fe_root ( chan ) / " los " / name / " export "
) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
} else {
// If the daughterboard doesn't expose its LO(s), assume it cannot
// export
return false ;
}
}
double set_tx_lo_freq (
const double freq ,
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_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 ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < double > (
tx_rf_fe_root ( chan ) / " los " / name / " freq " / " value "
) . set ( freq ) . 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_tx_lo_freq (
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_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 ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < double > ( tx_rf_fe_root ( chan ) / " los " / name / " freq " / " value " ) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
// Return actual RF frequency if the daughterboard doesn't expose
// its LO(s)
return _tree - > access < double > (
tx_rf_fe_root ( chan ) / " freq " / " value "
) . get ( ) ;
}
}
freq_range_t get_tx_lo_freq_range (
const std : : string & name = ALL_LOS ,
const size_t chan = 0
) {
if ( _tree - > exists ( tx_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 ( tx_rf_fe_root ( chan ) / " los " ) ) {
return _tree - > access < freq_range_t > (
tx_rf_fe_root ( chan ) / " los " / name / " freq " / " range "
) . get ( ) ;
} else {
throw uhd : : runtime_error ( " Could not find LO stage " + name ) ;
}
}
} else {
// Return the actual RF range if the daughterboard doesn't expose
// its LO(s)
return _tree - > access < meta_range_t > (
tx_rf_fe_root ( chan ) / " freq " / " range "
) . get ( ) ;
}
}
/**************************************************************************
* Gain control
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 ) {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " AGC enabled for this channel. Setting will be ignored. " ;
2015-03-05 23:24:46 +00:00
}
}
} 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 ) {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " AGC enabled for this channel. Setting will be ignored. " ;
2015-03-05 23:24:46 +00:00
}
}
}
}
/* 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
}
2018-01-10 01:52:48 +00:00
void set_rx_gain_profile ( const std : : string & profile , const size_t chan ) {
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " gains/all/profile/value " ) ) {
_tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " gains/all/profile/value " ) . set ( profile ) ;
}
} else {
for ( size_t c = 0 ; c < get_rx_num_channels ( ) ; c + + ) {
if ( _tree - > exists ( rx_rf_fe_root ( c ) / " gains/all/profile/value " ) ) {
_tree - > access < std : : string > ( rx_rf_fe_root ( chan ) / " gains/all/profile/value " ) . set ( profile ) ;
}
}
}
}
2018-01-17 02:27:12 +00:00
std : : string get_rx_gain_profile ( const size_t chan )
{
2018-01-10 01:52:48 +00:00
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " gains/all/profile/value " ) ) {
2018-01-17 02:27:12 +00:00
return _tree - > access < std : : string > (
rx_rf_fe_root ( chan ) / " gains/all/profile/value "
) . get ( ) ;
2018-01-10 01:52:48 +00:00
}
} else {
2018-01-17 02:27:12 +00:00
throw uhd : : runtime_error ( " Can't get RX gain profile from "
" all channels at once! " ) ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
return " " ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
std : : vector < std : : string > get_rx_gain_profile_names ( const size_t chan )
{
2018-01-10 01:52:48 +00:00
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " gains/all/profile/options " ) ) {
2018-01-17 02:27:12 +00:00
return _tree - > access < std : : vector < std : : string > > (
rx_rf_fe_root ( chan ) / " gains/all/profile/options "
) . get ( ) ;
2018-01-10 01:52:48 +00:00
}
} else {
2018-01-17 02:27:12 +00:00
throw uhd : : runtime_error ( " Can't get RX gain profile names from "
" all channels at once! " ) ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
return std : : vector < std : : string > ( ) ;
2018-01-10 01:52:48 +00:00
}
2015-02-03 16:20:09 +00:00
void set_normalized_rx_gain ( double gain , size_t chan = 0 )
{
2018-01-17 02:27:12 +00:00
if ( gain > 1.0 | | gain < 0.0 ) {
throw uhd : : runtime_error ( " Normalized gain out of range, "
" must be in [0, 1]. " ) ;
}
const gain_range_t gain_range = get_rx_gain_range ( ALL_GAINS , chan ) ;
const double abs_gain =
( gain * ( gain_range . stop ( ) - gain_range . start ( ) ) )
+ gain_range . start ( ) ;
set_rx_gain ( abs_gain , ALL_GAINS , chan ) ;
2015-02-03 16:20:09 +00:00
}
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " AGC is not available on this device. " ;
2015-03-05 23:24:46 +00:00
}
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 ) {
2017-05-15 20:55:09 +00:00
std : : vector < std : : string > sensor_names ;
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " sensors " ) ) {
sensor_names = _tree - > list ( rx_rf_fe_root ( chan ) / " sensors " ) ;
}
return sensor_names ;
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting DC offset compensation is not possible on this device. " ;
2014-04-30 12:19:21 +00:00
}
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting DC offset is not possible on this device. " ;
2014-04-30 12:19:21 +00:00
}
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 ) ;
}
}
2018-07-10 16:51:14 +00:00
meta_range_t get_rx_dc_offset_range ( size_t chan ) {
if ( _tree - > exists ( rx_fe_root ( chan ) / " dc_offset " / " range " ) ) {
return _tree - > access < uhd : : meta_range_t > ( rx_fe_root ( chan ) / " dc_offset " / " range " ) . get ( ) ;
} else {
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " This device does not support querying the RX DC offset range. " ;
return meta_range_t ( 0 , 0 ) ;
}
}
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting IQ imbalance compensation is not possible on this device. " ;
2015-02-20 18:49:53 +00:00
}
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting IQ balance is not possible on this device. " ;
2014-04-30 12:19:21 +00:00
}
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 ( ) ) ) ;
}
2017-02-08 00:37:25 +00:00
UHD_LOGGER_INFO ( " MULTI_USRP " ) < < " Selecting default TX front end spec: " < < spec . to_pp_string ( ) ;
2013-07-15 22:48:51 +00:00
}
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
}
2018-01-10 01:52:48 +00:00
void set_tx_gain_profile ( const std : : string & profile , const size_t chan ) {
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " gains/all/profile/value " ) ) {
_tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " gains/all/profile/value " ) . set ( profile ) ;
}
} else {
for ( size_t c = 0 ; c < get_tx_num_channels ( ) ; c + + ) {
if ( _tree - > exists ( tx_rf_fe_root ( c ) / " gains/all/profile/value " ) ) {
_tree - > access < std : : string > ( tx_rf_fe_root ( chan ) / " gains/all/profile/value " ) . set ( profile ) ;
}
}
}
}
2018-01-17 02:27:12 +00:00
std : : string get_tx_gain_profile ( const size_t chan )
{
2018-01-10 01:52:48 +00:00
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " gains/all/profile/value " ) ) {
2018-01-17 02:27:12 +00:00
return _tree - > access < std : : string > (
tx_rf_fe_root ( chan ) / " gains/all/profile/value "
) . get ( ) ;
2018-01-10 01:52:48 +00:00
}
} else {
2018-01-17 02:27:12 +00:00
throw uhd : : runtime_error ( " Can't get TX gain profile from "
" all channels at once! " ) ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
return " " ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
std : : vector < std : : string > get_tx_gain_profile_names ( const size_t chan )
{
2018-01-10 01:52:48 +00:00
if ( chan ! = ALL_CHANS ) {
if ( _tree - > exists ( tx_rf_fe_root ( chan ) / " gains/all/profile/options " ) ) {
2018-01-17 02:27:12 +00:00
return _tree - > access < std : : vector < std : : string > > (
tx_rf_fe_root ( chan ) / " gains/all/profile/options "
) . get ( ) ;
2018-01-10 01:52:48 +00:00
}
} else {
2018-01-17 02:27:12 +00:00
throw uhd : : runtime_error ( " Can't get TX gain profile names from "
" all channels at once! " ) ;
2018-01-10 01:52:48 +00:00
}
2018-01-17 02:27:12 +00:00
return std : : vector < std : : string > ( ) ;
2018-01-10 01:52:48 +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 ;
}
2017-04-09 06:43:20 +00:00
double norm_gain = ( get_tx_gain ( ALL_GAINS , chan ) - gain_range . start ( ) ) / gain_range_width ;
2015-02-03 16:20:09 +00:00
// 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 ) {
2017-05-15 20:55:09 +00:00
std : : vector < std : : string > sensor_names ;
if ( _tree - > exists ( rx_rf_fe_root ( chan ) / " sensors " ) ) {
sensor_names = _tree - > list ( tx_rf_fe_root ( chan ) / " sensors " ) ;
}
return sensor_names ;
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting DC offset is not possible on this device. " ;
2014-04-30 12:19:21 +00:00
}
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 ) ;
}
}
2018-07-10 16:51:14 +00:00
meta_range_t get_tx_dc_offset_range ( size_t chan ) {
if ( _tree - > exists ( tx_fe_root ( chan ) / " dc_offset " / " range " ) ) {
return _tree - > access < uhd : : meta_range_t > ( tx_fe_root ( chan ) / " dc_offset " / " range " ) . get ( ) ;
} else {
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " This device does not support querying the TX DC offset range. " ;
return meta_range_t ( 0 , 0 ) ;
}
}
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 {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < " Setting IQ balance is not possible on this device. " ;
2014-04-30 12:19:21 +00:00
}
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 " ) )
{
2017-02-10 07:19:55 +00:00
for ( const std : : string & name : _tree - > list ( mb_root ( mboard ) / " gpio " ) )
2014-02-04 19:04:07 +00:00
{
banks . push_back ( name ) ;
}
}
2017-02-10 07:19:55 +00:00
for ( const std : : string & name : _tree - > list ( mb_root ( mboard ) / " dboards " ) )
2014-02-04 19:04:07 +00:00
{
banks . push_back ( " RX " + name ) ;
banks . push_back ( " TX " + name ) ;
}
return banks ;
}
2018-03-14 23:38:23 +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
) {
2018-02-21 21:28:50 +00:00
std : : vector < std : : string > attr_value ;
2018-03-14 23:38:23 +00:00
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) ) {
2018-02-21 21:28:50 +00:00
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank / attr ) ) {
2018-03-14 23:38:23 +00:00
const auto attr_type = gpio_atr : : gpio_attr_rev_map . at ( attr ) ;
switch ( attr_type ) {
2018-02-21 21:28:50 +00:00
case gpio_atr : : GPIO_SRC :
2018-03-14 23:38:23 +00:00
throw uhd : : runtime_error (
" Can't set SRC attribute using integer value! "
) ;
2018-02-21 21:28:50 +00:00
break ;
case gpio_atr : : GPIO_CTRL :
2018-03-14 23:38:23 +00:00
case gpio_atr : : GPIO_DDR : {
attr_value = _tree - > access < std : : vector < std : : string > > (
mb_root ( mboard ) / " gpio " / bank / attr
) . get ( ) ;
2018-02-21 21:28:50 +00:00
UHD_ASSERT_THROW ( attr_value . size ( ) < = 32 ) ;
std : : bitset < 32 > bit_mask = std : : bitset < 32 > ( mask ) ;
std : : bitset < 32 > bit_value = std : : bitset < 32 > ( value ) ;
2018-03-14 23:38:23 +00:00
for ( size_t i = 0 ; i < bit_mask . size ( ) ; i + + ) {
if ( bit_mask [ i ] = = 1 ) {
2018-02-21 21:28:50 +00:00
attr_value [ i ] = gpio_atr : : attr_value_map . at ( attr_type ) . at ( bit_value [ i ] ) ;
}
}
2018-03-14 23:38:23 +00:00
_tree - > access < std : : vector < std : : string > > (
mb_root ( mboard ) / " gpio " / bank / attr
) . set ( attr_value ) ;
2018-02-21 21:28:50 +00:00
}
2018-03-14 23:38:23 +00:00
break ;
2018-02-21 21:28:50 +00:00
default : {
2018-03-14 23:38:23 +00:00
const uint32_t current = _tree - > access < uint32_t > (
mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ;
2018-02-21 21:28:50 +00:00
const uint32_t new_value = ( current & ~ mask ) | ( value & mask ) ;
_tree - > access < uint32_t > ( mb_root ( mboard ) / " gpio " / bank / attr ) . set ( new_value ) ;
}
2018-03-14 23:38:23 +00:00
break ;
2018-02-21 21:28:50 +00:00
}
return ;
2018-03-14 23:38:23 +00:00
} else {
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no gpio attribute: `%s': \n " )
% attr
) ) ;
2018-02-21 21:28:50 +00:00
}
}
2018-03-14 23:38:23 +00:00
if ( bank . size ( ) > 2 and bank [ 1 ] = = ' X ' ) {
2018-02-21 21:28:50 +00:00
const std : : string name = bank . substr ( 2 ) ;
2018-03-14 23:38:23 +00:00
const dboard_iface : : unit_t unit =
( bank [ 0 ] = = ' R ' )
? dboard_iface : : UNIT_RX
: dboard_iface : : UNIT_TX ;
auto iface = _tree - > access < dboard_iface : : sptr > (
mb_root ( mboard ) / " dboards " / name / " iface " ) . get ( ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_CTRL ) )
iface - > set_pin_ctrl ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_DDR ) )
iface - > set_gpio_ddr ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_OUT ) )
iface - > set_gpio_out ( unit , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_ATR_0X ) )
iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_IDLE , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_ATR_RX ) )
iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_RX_ONLY , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_ATR_TX ) )
iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_TX_ONLY , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_ATR_XX ) )
iface - > set_atr_reg ( unit , gpio_atr : : ATR_REG_FULL_DUPLEX , uint16_t ( value ) , uint16_t ( mask ) ) ;
if ( attr = = gpio_atr : : gpio_attr_map . at ( gpio_atr : : GPIO_SRC ) ) {
2018-02-21 21:28:50 +00:00
throw uhd : : runtime_error ( " Setting gpio source does not supported in daughter board. " ) ;
}
2018-03-14 15:31:33 +00:00
return ;
2018-02-21 21:28:50 +00:00
}
2018-03-14 23:38:23 +00:00
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no GPIO bank `%s' " )
% bank
) ) ;
2018-02-21 21:28:50 +00:00
}
2018-03-14 23:38:23 +00:00
void set_gpio_attr (
const std : : string & bank ,
const std : : string & attr ,
const std : : string & str_value ,
const uint32_t mask ,
const size_t mboard
) {
const auto attr_type = gpio_atr : : gpio_attr_rev_map . at ( attr ) ;
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) ) {
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank / attr ) ) {
2018-02-21 21:28:50 +00:00
switch ( attr_type ) {
case gpio_atr : : GPIO_SRC :
case gpio_atr : : GPIO_CTRL :
case gpio_atr : : GPIO_DDR : {
2018-03-14 23:38:23 +00:00
auto attr_value =
_tree - > access < std : : vector < std : : string > > (
mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ;
UHD_ASSERT_THROW ( attr_value . size ( ) < = 32 ) ;
2018-02-21 21:28:50 +00:00
std : : bitset < 32 > bit_mask = std : : bitset < 32 > ( mask ) ;
2018-03-14 23:38:23 +00:00
for ( size_t i = 0 ; i < bit_mask . size ( ) ; i + + ) {
if ( bit_mask [ i ] = = 1 ) {
attr_value [ i ] = str_value ;
}
}
_tree - > access < std : : vector < std : : string > > (
mb_root ( mboard ) / " gpio " / bank / attr
) . set ( attr_value ) ;
2018-02-21 21:28:50 +00:00
}
2018-03-14 23:38:23 +00:00
break ;
default : {
const uint32_t value =
gpio_atr : : gpio_attr_value_pair . at ( attr ) . at ( str_value ) = = 0 ? - 1 : 0 ;
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 ) ;
}
break ;
2018-02-21 21:28:50 +00:00
}
return ;
2018-03-14 23:38:23 +00:00
} else {
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no gpio attribute `%s' " )
% attr
) ) ;
}
}
// If the bank is not in the prop tree, convert string value to integer
// value and have it handled by the other set_gpio_attr()
const uint32_t value =
gpio_atr : : gpio_attr_value_pair . at ( attr ) . at ( str_value ) = = 0
? - 1
: 0 ;
set_gpio_attr (
bank ,
attr ,
value ,
mask ,
mboard
) ;
2014-02-04 19:04:07 +00:00
}
2018-03-14 23:38:23 +00:00
uint32_t get_gpio_attr (
const std : : string & bank ,
const std : : string & attr ,
const size_t mboard
) {
2018-02-21 21:28:50 +00:00
std : : vector < std : : string > str_val ;
2018-03-14 23:38:23 +00:00
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) ) {
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank / attr ) ) {
const auto attr_type = gpio_atr : : gpio_attr_rev_map . at ( attr ) ;
2018-02-21 21:28:50 +00:00
switch ( attr_type ) {
case gpio_atr : : GPIO_SRC :
2018-03-14 23:38:23 +00:00
throw uhd : : runtime_error ( " Can't set SRC attribute using integer value " ) ;
2018-02-21 21:28:50 +00:00
case gpio_atr : : GPIO_CTRL :
2018-03-14 23:38:23 +00:00
case gpio_atr : : GPIO_DDR : {
str_val = _tree - > access < std : : vector < std : : string > > (
mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ;
2018-02-21 21:28:50 +00:00
uint32_t val = 0 ;
2018-03-14 23:38:23 +00:00
for ( size_t i = 0 ; i < str_val . size ( ) ; i + + ) {
val + = usrp : : gpio_atr : : gpio_attr_value_pair . at ( attr ) . at ( str_val [ i ] ) < < i ;
2018-02-21 21:28:50 +00:00
}
return val ;
}
2018-03-14 23:38:23 +00:00
default :
return uint32_t ( _tree - > access < uint64_t > (
mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ) ;
2018-02-21 21:28:50 +00:00
}
return 0 ;
2018-03-14 23:38:23 +00:00
} else {
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no gpio attribute: `%s' " )
% attr
) ) ;
2018-02-21 21:28:50 +00:00
}
2014-02-04 19:04:07 +00:00
}
2018-03-14 23:38:23 +00:00
if ( bank . size ( ) > 2 and bank [ 1 ] = = ' X ' ) {
2014-02-04 19:04:07 +00:00
const std : : string name = bank . substr ( 2 ) ;
const dboard_iface : : unit_t unit = ( bank [ 0 ] = = ' R ' ) ? dboard_iface : : UNIT_RX : dboard_iface : : UNIT_TX ;
2018-03-14 23:38:23 +00:00
auto iface = _tree - > access < dboard_iface : : sptr > (
mb_root ( mboard ) / " dboards " / name / " iface " ) . get ( ) ;
2018-02-21 21:28:50 +00:00
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 ) ;
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 ) ;
}
2018-03-14 23:38:23 +00:00
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no gpio bank `%s' " )
% bank
) ) ;
2018-02-21 21:28:50 +00:00
}
2018-03-14 23:38:23 +00:00
std : : vector < std : : string > get_gpio_string_attr (
const std : : string & bank ,
const std : : string & attr ,
const size_t mboard
) {
const auto attr_type = gpio_atr : : gpio_attr_rev_map . at ( attr ) ;
auto str_val = std : : vector < std : : string > ( 32 , gpio_atr : : default_attr_value_map . at ( attr_type ) ) ;
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank ) ) {
if ( _tree - > exists ( mb_root ( mboard ) / " gpio " / bank / attr ) ) {
const auto attr_type = gpio_atr : : gpio_attr_rev_map . at ( attr ) ;
2018-02-21 21:28:50 +00:00
switch ( attr_type ) {
case gpio_atr : : GPIO_SRC :
case gpio_atr : : GPIO_CTRL :
2018-03-14 23:38:23 +00:00
case gpio_atr : : GPIO_DDR :
2018-02-21 21:28:50 +00:00
return _tree - > access < std : : vector < std : : string > > ( mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ;
2018-03-14 23:38:23 +00:00
default : {
2018-02-21 21:28:50 +00:00
uint32_t value = uint32_t ( _tree - > access < uint32_t > ( mb_root ( mboard ) / " gpio " / bank / attr ) . get ( ) ) ;
std : : bitset < 32 > bit_value = std : : bitset < 32 > ( value ) ;
for ( size_t i = 0 ; i < bit_value . size ( ) ; i + + )
{
str_val [ i ] = bit_value [ i ] = = 0 ? " LOW " : " HIGH " ;
}
return str_val ;
}
}
}
2018-03-14 23:38:23 +00:00
else {
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no gpio attribute: `%s' " )
% attr
) ) ;
2018-02-21 21:28:50 +00:00
}
}
2018-03-14 23:38:23 +00:00
throw uhd : : runtime_error ( str (
boost : : format ( " The hardware has no support for given gpio bank name `%s' " )
% bank
) ) ;
2014-02-04 19:04:07 +00:00
}
2018-03-14 23:38:23 +00:00
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
{
2017-06-28 02:06:50 +00:00
const std : : string tree_path = " /mboards/ " + std : : to_string ( mboard ) ;
2017-04-05 02:00:30 +00:00
if ( _tree - > exists ( tree_path ) ) {
return tree_path ;
} else {
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::mb_root(%u) - path not found " ) % mboard ) ) ;
}
2013-07-15 22:48:51 +00:00
}
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
{
2017-06-28 02:06:50 +00:00
const std : : string tree_path = mb_root ( mcp . mboard ) / " rx_dsps " / mcp . chan ;
2017-04-05 02:00:30 +00:00
if ( _tree - > exists ( tree_path ) ) {
return tree_path ;
} else {
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::rx_dsp_root(%u) - mcp(%u) - path not found " ) % chan % mcp . chan ) ) ;
}
2013-07-15 22:48:51 +00:00
}
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
{
2017-06-28 02:06:50 +00:00
const std : : string tree_path = mb_root ( mcp . mboard ) / " tx_dsps " / mcp . chan ;
2017-04-05 02:00:30 +00:00
if ( _tree - > exists ( tree_path ) ) {
return tree_path ;
} else {
throw uhd : : index_error ( str ( boost : : format ( " multi_usrp::tx_dsp_root(%u) - mcp(%u) - path not found " ) % chan % mcp . chan ) ) ;
}
2013-07-15 22:48:51 +00:00
}
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
}
2018-04-02 21:57:26 +00:00
size_t get_radio_index ( const std : : string slot_name )
{
if ( slot_name = = " A " ) {
return 0 ;
} else if ( slot_name = = " B " ) {
return 1 ;
} else if ( slot_name = = " C " ) {
return 2 ;
} else if ( slot_name = = " D " ) {
return 3 ;
} else {
throw uhd : : key_error ( str (
boost : : format ( " [multi_usrp]: radio slot name %s out of supported range. " )
% slot_name
) ) ;
}
}
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 ( ) ;
2017-02-10 07:19:55 +00:00
for ( 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
}
2017-02-10 07:19:55 +00:00
for ( 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 ( ) ;
2017-02-10 07:19:55 +00:00
for ( 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
}
2017-02-10 07:19:55 +00:00
for ( 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 ;
2017-02-10 07:19:55 +00:00
for ( const size_t chan : args . channels ) {
2014-02-28 17:14:31 +00:00
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 ) {
2017-02-08 00:37:25 +00:00
UHD_LOGGER_WARNING ( " MULTI_USRP " ) < < boost : : format (
2014-02-28 17:14:31 +00:00
" The total sum of rates (%f MSps on %u channels) exceeds the maximum capacity of the connection. \n "
" This can cause %s. "
2017-02-08 00:37:25 +00:00
) % ( sum_rate / 1e6 ) % args . channels . size ( ) % ( is_tx ? " underruns (U) " : " overflows (O) " ) ;
2014-02-28 17:14:31 +00:00
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 ) {
2017-04-06 06:18:08 +00:00
UHD_LOGGER_TRACE ( " MULTI_USRP " ) < < " multi_usrp::make with args " < < dev_addr . to_pp_string ( ) ;
2010-10-17 01:07:10 +00:00
return sptr ( new multi_usrp_impl ( dev_addr ) ) ;
}