bladerf: initial support for new bladeRF hardware

Relies on some new libbladeRF API calls. Has been tested
with gqrx on new bladeRF hardware (as a source) but have
not yet tested sink, or existing bladeRF hardware.
This commit is contained in:
Rey Tucker 2017-05-26 10:16:33 -04:00 committed by Dimitri Stolnikov
parent 0b5c3911f7
commit 56da34f7f2
6 changed files with 344 additions and 299 deletions

View File

@ -48,6 +48,10 @@ using namespace boost::assign;
boost::mutex bladerf_common::_devs_mutex;
std::list<boost::weak_ptr<struct bladerf> > bladerf_common::_devs;
// name of system-wide gain
//(internal only, doesn't match any libbladeRF gain stage)
static const char* SYSTEM_GAIN_NAME = "System";
bladerf_common::bladerf_common() :
_conv_buf(NULL),
_conv_buf_size(4096),
@ -105,6 +109,7 @@ bladerf_sptr bladerf_common::open(const std::string &device_name)
int rv;
struct bladerf *raw_dev;
struct bladerf_devinfo devinfo;
std::string boardname;
boost::unique_lock<boost::mutex> lock(_devs_mutex);
@ -127,6 +132,18 @@ bladerf_sptr bladerf_common::open(const std::string &device_name)
_devs.push_back(boost::weak_ptr<struct bladerf>(dev));
// TODO: This does NOT get called if early cached_dev return occurs
boardname = std::string(bladerf_get_board_name(raw_dev));
if( "bladerf1" == boardname ) {
_boardtype = BLADERF_REV_1;
} else if( "bladerf2" == boardname ) {
_boardtype = BLADERF_REV_2;
} else {
std::cerr << "board name \"" << boardname << "\" unknown" << std::endl;
_boardtype = BLADERF_REV_INVALID;
};
return dev;
}
@ -135,6 +152,7 @@ void bladerf_common::set_loopback_mode(const std::string &loopback)
bladerf_loopback mode;
int status;
// TODO: update for bladeRF 2
if (loopback == "bb_txlpf_rxvga2") {
mode = BLADERF_LB_BB_TXLPF_RXVGA2;
} else if (loopback == "bb_txlpf_rxlpf") {
@ -191,6 +209,8 @@ bool bladerf_common::start(bladerf_module module)
{
int ret;
bladerf_format format;
bladerf_channel_layout layout;
bladerf_direction direction;
if (_use_metadata) {
format = BLADERF_FORMAT_SC16_Q11_META;
@ -198,7 +218,21 @@ bool bladerf_common::start(bladerf_module module)
format = BLADERF_FORMAT_SC16_Q11;
}
ret = bladerf_sync_config(_dev.get(), module, format,
// TODO: DRY
// TODO: MIMO
if (BLADERF_MODULE_RX == module) {
layout = BLADERF_RX_X1;
direction = BLADERF_RX;
} else if (BLADERF_MODULE_TX == module) {
layout = BLADERF_TX_X1;
direction = BLADERF_TX;
} else {
std::cerr << _pfx << "invalid module: "
<< module << std::endl;
return false;
}
ret = bladerf_sync_config(_dev.get(), layout, format,
_num_buffers, _samples_per_buffer,
_num_transfers, _stream_timeout_ms);
@ -208,7 +242,7 @@ bool bladerf_common::start(bladerf_module module)
return false;
}
ret = bladerf_enable_module(_dev.get(), module, true);
ret = bladerf_enable_module(_dev.get(), direction, true);
if ( ret != 0 ) {
std::cerr << _pfx << "bladerf_enable_module failed: "
<< bladerf_strerror(ret) << std::endl;
@ -221,8 +255,21 @@ bool bladerf_common::start(bladerf_module module)
bool bladerf_common::stop(bladerf_module module)
{
int ret;
bladerf_direction direction;
ret = bladerf_enable_module(_dev.get(), module, false);
// TODO: DRY
// TODO: MIMO
if (BLADERF_MODULE_RX == module) {
direction = BLADERF_RX;
} else if (BLADERF_MODULE_TX == module) {
direction = BLADERF_TX;
} else {
std::cerr << _pfx << "invalid module: "
<< module << std::endl;
return false;
}
ret = bladerf_enable_module(_dev.get(), direction, false);
if ( ret != 0 ) {
std::cerr << _pfx << "bladerf_enable_modue failed: "
@ -491,20 +538,40 @@ void bladerf_common::init(dict_t &dict, bladerf_module module)
}
}
osmosdr::freq_range_t bladerf_common::freq_range()
osmosdr::freq_range_t bladerf_common::freq_range(bladerf_channel chan)
{
/* assuming the same for RX & TX */
return osmosdr::freq_range_t( _xb_200_attached ? 0 : 280e6, BLADERF_FREQUENCY_MAX );
struct bladerf_range brf_range;
int ret;
ret = bladerf_get_frequency_range( _dev.get(), chan, &brf_range );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"bladerf_get_frequency_range returned " +
boost::lexical_cast<std::string>(ret) );
} else {
return osmosdr::freq_range_t((double)brf_range.min, (double)brf_range.max, (double)brf_range.step);
};
}
osmosdr::meta_range_t bladerf_common::sample_rates()
{
osmosdr::meta_range_t sample_rates;
bladerf_range brf_sample_rates;
int ret;
/* assuming the same for RX & TX */
sample_rates += osmosdr::range_t( 160e3, 200e3, 40e3 );
sample_rates += osmosdr::range_t( 300e3, 900e3, 100e3 );
sample_rates += osmosdr::range_t( 1e6, 40e6, 1e6 );
ret = bladerf_get_sample_rate_range( _dev.get(), BLADERF_CHANNEL_RX(0), &brf_sample_rates );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"bladerf_get_sample_rate_range returned " +
boost::lexical_cast<std::string>(ret) );
}
sample_rates += osmosdr::range_t( brf_sample_rates.min, brf_sample_rates.max/4.0, brf_sample_rates.max/16.0 );
sample_rates += osmosdr::range_t( brf_sample_rates.max/4.0, brf_sample_rates.max/2.0, brf_sample_rates.max/8.0 );
sample_rates += osmosdr::range_t( brf_sample_rates.max/2.0, brf_sample_rates.max, brf_sample_rates.max/4.0 );
return sample_rates;
}
@ -513,14 +580,18 @@ osmosdr::freq_range_t bladerf_common::filter_bandwidths()
{
/* the same for RX & TX according to the datasheet */
osmosdr::freq_range_t bandwidths;
bladerf_range brf_range;
int ret;
std::vector<double> half_bandwidths; /* in MHz */
half_bandwidths += \
0.75, 0.875, 1.25, 1.375, 1.5, 1.92, 2.5,
2.75, 3, 3.5, 4.375, 5, 6, 7, 10, 14;
ret = bladerf_get_bandwidth_range( _dev.get(), BLADERF_CHANNEL_RX(0), &brf_range );
BOOST_FOREACH( double half_bw, half_bandwidths )
bandwidths += osmosdr::range_t( half_bw * 2e6 );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"bladerf_get_bandwidth_range returned " +
boost::lexical_cast<std::string>(ret) );
}
bandwidths += osmosdr::range_t(brf_range.min, brf_range.max, brf_range.step);
return bandwidths;
}
@ -560,6 +631,15 @@ std::vector< std::string > bladerf_common::devices()
return ret;
}
size_t bladerf_common::get_num_channels(bladerf_module module)
{
if (BLADERF_REV_2 == _boardtype) {
return 1; // TODO: should be 2 but it ain't working yet
} else {
return 1;
}
}
double bladerf_common::set_sample_rate( bladerf_module module, double rate )
{
int status;
@ -601,6 +681,177 @@ double bladerf_common::get_sample_rate( bladerf_module module )
return ret;
}
osmosdr::freq_range_t bladerf_common::get_freq_range( size_t chan )
{
return freq_range((bladerf_channel)chan);
}
double bladerf_common::set_center_freq( double freq, size_t chan )
{
int ret;
/* Check frequency range */
if( freq < get_freq_range( chan ).start() ||
freq > get_freq_range( chan ).stop() ) {
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
} else {
ret = bladerf_set_frequency( _dev.get(), (bladerf_channel)chan, (uint64_t)freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"failed to set center frequency " +
boost::lexical_cast<std::string>(freq) + ": " +
std::string(bladerf_strerror(ret)) );
}
}
return get_center_freq( chan );
}
double bladerf_common::get_center_freq( size_t chan )
{
uint64_t freq;
int ret;
ret = bladerf_get_frequency( _dev.get(), (bladerf_channel)chan, &freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"failed to get center frequency: " +
std::string(bladerf_strerror(ret)) );
}
return (double)freq;
}
std::vector<std::string> bladerf_common::get_gain_names( size_t chan )
{
const size_t max_count = 16;
std::vector< std::string > names;
char *gain_names[max_count];
int ret;
memset(&gain_names, 0, sizeof(gain_names));
names += SYSTEM_GAIN_NAME;
ret = bladerf_get_gain_stages( _dev.get(), (bladerf_channel)chan, (const char**)&gain_names, max_count);
if(ret < 0) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"failed to get gain stages: " +
std::string(bladerf_strerror(ret)) );
}
for(char **p = gain_names; *p != NULL; ++p) {
char *tmp = *p;
names += std::string(tmp);
};
return names;
}
osmosdr::gain_range_t bladerf_common::get_gain_range( size_t chan )
{
/* This is an overall system gain range. */
return get_gain_range( SYSTEM_GAIN_NAME, chan );
}
osmosdr::gain_range_t bladerf_common::get_gain_range( const std::string & name, size_t chan )
{
osmosdr::gain_range_t range;
struct bladerf_range brf_range;
int ret;
if( name == SYSTEM_GAIN_NAME ) {
ret = bladerf_get_gain_range( _dev.get(), (bladerf_channel)chan, &brf_range );
} else {
ret = bladerf_get_gain_stage_range( _dev.get(), (bladerf_channel)chan, name.c_str(), &brf_range);
}
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"bladerf_get_gain_range " + name +
" error: " +
std::string(bladerf_strerror(ret)) );
}
range = osmosdr::gain_range_t( brf_range.min, brf_range.max, brf_range.step );
return range;
}
bool bladerf_common::set_gain_mode( bool automatic, size_t chan )
{
return false;
}
bool bladerf_common::get_gain_mode( size_t chan )
{
return false;
}
double bladerf_common::set_gain( double gain, size_t chan )
{
return set_gain( gain, SYSTEM_GAIN_NAME, chan );
}
double bladerf_common::set_gain( double gain, const std::string & name, size_t chan )
{
int ret = 0;
if( name == SYSTEM_GAIN_NAME ) {
ret = bladerf_set_gain( _dev.get(), (bladerf_channel)chan, int(gain) );
} else {
ret = bladerf_set_gain_stage( _dev.get(), (bladerf_channel)chan, name.c_str(), int(gain) );
}
/* Check for errors */
if( ret ) {
std::string errmsg = (std::string(__FUNCTION__) + " " +
"could not set " + name + " gain: " +
std::string(bladerf_strerror(ret)));
if ( BLADERF_ERR_UNSUPPORTED == ret ) {
// unsupported, but not worth crashing out
std::cerr << errmsg << std::endl;
} else {
throw std::runtime_error(errmsg);
}
}
return get_gain( name, chan );
}
double bladerf_common::get_gain( size_t chan )
{
/* TODO: This is an overall system gain that has to be set */
return get_gain( SYSTEM_GAIN_NAME, chan );
}
double bladerf_common::get_gain( const std::string & name, size_t chan )
{
int g;
int ret = 0;
if( name == SYSTEM_GAIN_NAME ) {
ret = bladerf_get_gain( _dev.get(), (bladerf_channel)chan, &g );
} else {
ret = bladerf_get_gain_stage( _dev.get(), (bladerf_channel)chan, name.c_str(), &g );
}
/* Check for errors */
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"could not get " + name + " gain: " +
std::string(bladerf_strerror(ret)) );
}
return (double)g;
}
double bladerf_common::set_bb_gain( double gain, size_t chan )
{
return set_gain( gain, SYSTEM_GAIN_NAME, chan );
}
int bladerf_common::set_dc_offset(bladerf_module module, const std::complex<double> &offset, size_t chan)
{
int ret = 0;

View File

@ -55,15 +55,39 @@ public:
virtual ~bladerf_common();
protected:
typedef enum {
BLADERF_REV_INVALID,
BLADERF_REV_1,
BLADERF_REV_2
} bladerf_boards;
/* Handle initialized and parameters common to both source & sink */
void init(dict_t &dict, bladerf_module module);
bool start(bladerf_module module);
bool stop(bladerf_module module);
size_t get_num_channels(bladerf_module module);
double set_sample_rate(bladerf_module module, double rate);
double get_sample_rate(bladerf_module module);
osmosdr::freq_range_t get_freq_range(size_t chan = 0);
double set_center_freq(double freq, size_t chan = 0);
double get_center_freq(size_t chan = 0);
std::vector<std::string> get_gain_names( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
bool set_gain_mode( bool automatic, size_t chan = 0 );
bool get_gain_mode( size_t chan = 0 );
double set_gain( double gain, size_t chan = 0 );
double set_gain( double gain, const std::string & name, size_t chan = 0 );
double get_gain( size_t chan = 0 );
double get_gain( const std::string & name, size_t chan = 0 );
double set_bb_gain( double gain, size_t chan = 0 );
int set_dc_offset(bladerf_module module, const std::complex<double> &offset, size_t chan);
int set_iq_balance(bladerf_module module, const std::complex<double> &balance, size_t chan);
@ -74,7 +98,7 @@ protected:
void set_smb_frequency(double frequency);
double get_smb_frequency();
osmosdr::freq_range_t freq_range();
osmosdr::freq_range_t freq_range(bladerf_channel chan);
osmosdr::meta_range_t sample_rates();
osmosdr::freq_range_t filter_bandwidths();
@ -82,6 +106,8 @@ protected:
bladerf_sptr _dev;
bladerf_boards _boardtype;
size_t _num_buffers;
size_t _samples_per_buffer;
size_t _num_transfers;
@ -92,9 +118,6 @@ protected:
bool _use_metadata;
osmosdr::gain_range_t _vga1_range;
osmosdr::gain_range_t _vga2_range;
std::string _pfx;
bool _xb_200_attached;

View File

@ -67,11 +67,11 @@ bladerf_sink_c_sptr make_bladerf_sink_c (const std::string &args)
* (2nd & 3rd args to gr_block's constructor). The input and
* output signatures are used by the runtime system to
* check that a valid number and type of inputs and outputs
* are connected to this block. In this case, we accept
* only 0 input and 1 output.
* are connected to this block. In this case, we accept either
* 1 or 2 inputs.
*/
static const int MIN_IN = 1; // mininum number of input streams
static const int MAX_IN = 1; // maximum number of input streams
static const int MAX_IN = 2; // maximum number of input streams
static const int MIN_OUT = 0; // minimum number of output streams
static const int MAX_OUT = 0; // maximum number of output streams
@ -87,13 +87,6 @@ bladerf_sink_c::bladerf_sink_c (const std::string &args)
/* Perform src/sink agnostic initializations */
init(dict, BLADERF_MODULE_TX);
/* Set the range of VGA1, VGA1GAINT[7:0] */
_vga1_range = osmosdr::gain_range_t( -35, -4, 1 );
/* Set the range of VGA2, VGA2GAIN[4:0] */
_vga2_range = osmosdr::gain_range_t( 0, 25, 1 );
}
bool bladerf_sink_c::start()
@ -297,8 +290,7 @@ std::vector<std::string> bladerf_sink_c::get_devices()
size_t bladerf_sink_c::get_num_channels()
{
/* We only support a single channel for each bladeRF */
return 1;
return bladerf_common::get_num_channels(BLADERF_MODULE_RX);
}
osmosdr::meta_range_t bladerf_sink_c::get_sample_rates()
@ -318,43 +310,17 @@ double bladerf_sink_c::get_sample_rate()
osmosdr::freq_range_t bladerf_sink_c::get_freq_range(size_t chan)
{
return freq_range();
return bladerf_common::get_freq_range(chan);
}
double bladerf_sink_c::set_center_freq(double freq, size_t chan)
{
int ret;
/* Check frequency range */
if( freq < get_freq_range( chan ).start() ||
freq > get_freq_range( chan ).stop() ) {
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
} else {
ret = bladerf_set_frequency( _dev.get(), BLADERF_MODULE_TX, (uint32_t)freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Failed to set center frequency " +
boost::lexical_cast<std::string>(freq) +
":" + std::string(bladerf_strerror(ret)));
}
}
return get_center_freq( chan );
return bladerf_common::set_center_freq(freq, chan);
}
double bladerf_sink_c::get_center_freq(size_t chan)
{
uint32_t freq;
int ret;
ret = bladerf_get_frequency( _dev.get(), BLADERF_MODULE_TX, &freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Failed to get center frequency:" +
std::string(bladerf_strerror(ret)));
}
return (double)freq;
return bladerf_common::get_center_freq(chan);
}
double bladerf_sink_c::set_freq_corr( double ppm, size_t chan )
@ -371,114 +337,52 @@ double bladerf_sink_c::get_freq_corr( size_t chan )
std::vector<std::string> bladerf_sink_c::get_gain_names( size_t chan )
{
std::vector< std::string > names;
names += "VGA1", "VGA2";
return names;
return bladerf_common::get_gain_names(chan);
}
osmosdr::gain_range_t bladerf_sink_c::get_gain_range( size_t chan )
{
/* TODO: This is an overall system gain range. Given the VGA1 and VGA2
how much total gain can we have in the system */
return get_gain_range( "VGA2", chan ); /* we use only VGA2 here for now */
return bladerf_common::get_gain_range(chan);
}
osmosdr::gain_range_t bladerf_sink_c::get_gain_range( const std::string & name, size_t chan )
{
osmosdr::gain_range_t range;
if( name == "VGA1" ) {
range = _vga1_range;
} else if( name == "VGA2" ) {
range = _vga2_range;
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Requested an invalid gain element " + name );
}
return range;
return bladerf_common::get_gain_range(name, chan);
}
bool bladerf_sink_c::set_gain_mode( bool automatic, size_t chan )
{
return false;
return bladerf_common::set_gain_mode(automatic, chan);
}
bool bladerf_sink_c::get_gain_mode( size_t chan )
{
return false;
return bladerf_common::get_gain_mode(chan);
}
double bladerf_sink_c::set_gain( double gain, size_t chan )
{
return set_gain( gain, "VGA2", chan ); /* we use only VGA2 here for now */
return bladerf_common::set_gain(gain, chan);
}
double bladerf_sink_c::set_gain( double gain, const std::string & name, size_t chan)
{
int ret = 0;
if( name == "VGA1" ) {
ret = bladerf_set_txvga1( _dev.get(), (int)gain );
} else if( name == "VGA2" ) {
ret = bladerf_set_txvga2( _dev.get(), (int)gain );
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Requested to set the gain " +
"of an unknown gain element " + name );
}
/* Check for errors */
if( ret ) {
throw std::runtime_error(std::string(__FUNCTION__) + " " +
"Could not set " + name + " gain, error " +
std::string(bladerf_strerror(ret)));
}
return get_gain( name, chan );
return bladerf_common::set_gain(gain, name, chan);
}
double bladerf_sink_c::get_gain( size_t chan )
{
return get_gain( "VGA2", chan ); /* we use only VGA2 here for now */
return bladerf_common::get_gain(chan);
}
double bladerf_sink_c::get_gain( const std::string & name, size_t chan )
{
int g;
int ret = 0;
if( name == "VGA1" ) {
ret = bladerf_get_txvga1( _dev.get(), &g );
} else if( name == "VGA2" ) {
ret = bladerf_get_txvga2( _dev.get(), &g );
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Requested to get the gain " +
"of an unknown gain element " + name );
}
/* Check for errors */
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Could not get " + name + " gain, error " +
std::string(bladerf_strerror(ret)));
}
return (double)g;
return bladerf_common::get_gain(name, chan);
}
double bladerf_sink_c::set_bb_gain( double gain, size_t chan )
{
/* for TX, only VGA1 is in the BB path */
osmosdr::gain_range_t bb_gains = get_gain_range( "VGA1", chan );
double clip_gain = bb_gains.clip( gain, true );
gain = set_gain( clip_gain, "VGA1", chan );
return gain;
return bladerf_common::set_bb_gain(gain, chan);
}
std::vector< std::string > bladerf_sink_c::get_antennas( size_t chan )

View File

@ -92,6 +92,7 @@ public:
osmosdr::freq_range_t get_freq_range(size_t chan = 0);
double set_center_freq(double freq, size_t chan = 0);
double get_center_freq(size_t chan = 0);
double set_freq_corr( double ppm, size_t chan = 0 );
double get_freq_corr( size_t chan = 0 );

View File

@ -59,13 +59,13 @@ bladerf_source_c_sptr make_bladerf_source_c (const std::string &args)
* (2nd & 3rd args to gr_block's constructor). The input and
* output signatures are used by the runtime system to
* check that a valid number and type of inputs and outputs
* are connected to this block. In this case, we accept
* only 0 input and 1 output.
* are connected to this block. In this case, we accept either
* 1 or 2 outputs.
*/
static const int MIN_IN = 0; // mininum number of input streams
static const int MAX_IN = 0; // maximum number of input streams
static const int MIN_OUT = 1; // minimum number of output streams
static const int MAX_OUT = 1; // maximum number of output streams
static const int MAX_OUT = 2; // maximum number of output streams
/*
* The private constructor
@ -103,15 +103,6 @@ bladerf_source_c::bladerf_source_c (const std::string &args)
}
}
/* Set the range of LNA, G_LNA_RXFE[1:0] */
_lna_range = osmosdr::gain_range_t( 0, 6, 3 );
/* Set the range of VGA1, RFB_TIA_RXFE[6:0], nonlinear mapping done inside the lib */
_vga1_range = osmosdr::gain_range_t( 5, 30, 1 );
/* Set the range of VGA2 VGA2GAIN[4:0], not recommended to be used above 30dB */
_vga2_range = osmosdr::gain_range_t( 0, 30, 3 );
/* Warn user about using an old FPGA version, as we no longer strip off the
* markers that were pressent in the pre-v0.0.1 FPGA */
if (bladerf_fpga_version( _dev.get(), &fpga_version ) != 0) {
@ -197,8 +188,7 @@ std::vector<std::string> bladerf_source_c::get_devices()
size_t bladerf_source_c::get_num_channels()
{
/* We only support a single channel for each bladeRF */
return 1;
return bladerf_common::get_num_channels(BLADERF_MODULE_RX);
}
osmosdr::meta_range_t bladerf_source_c::get_sample_rates()
@ -218,43 +208,17 @@ double bladerf_source_c::get_sample_rate()
osmosdr::freq_range_t bladerf_source_c::get_freq_range(size_t chan)
{
return freq_range();
return bladerf_common::get_freq_range(chan);
}
double bladerf_source_c::set_center_freq(double freq, size_t chan)
{
int ret;
/* Check frequency range */
if( freq < get_freq_range( chan ).start() ||
freq > get_freq_range( chan ).stop() ) {
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
} else {
ret = bladerf_set_frequency( _dev.get(), BLADERF_MODULE_RX, (uint32_t)freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"failed to set center frequency " +
boost::lexical_cast<std::string>(freq) + ": " +
std::string(bladerf_strerror(ret)) );
}
}
return get_center_freq( chan );
return bladerf_common::set_center_freq(freq, chan);
}
double bladerf_source_c::get_center_freq(size_t chan)
{
uint32_t freq;
int ret;
ret = bladerf_get_frequency( _dev.get(), BLADERF_MODULE_RX, &freq );
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"failed to get center frequency: " +
std::string(bladerf_strerror(ret)) );
}
return (double)freq;
return bladerf_common::get_center_freq(chan);
}
double bladerf_source_c::set_freq_corr( double ppm, size_t chan )
@ -271,150 +235,52 @@ double bladerf_source_c::get_freq_corr( size_t chan )
std::vector<std::string> bladerf_source_c::get_gain_names( size_t chan )
{
std::vector< std::string > names;
names += "LNA", "VGA1", "VGA2";
return names;
return bladerf_common::get_gain_names(chan);
}
osmosdr::gain_range_t bladerf_source_c::get_gain_range( size_t chan )
{
/* TODO: This is an overall system gain range. Given the LNA, VGA1 and VGA2
how much total gain can we have in the system */
return get_gain_range( "LNA", chan ); /* we use only LNA here for now */
return bladerf_common::get_gain_range(chan);
}
osmosdr::gain_range_t bladerf_source_c::get_gain_range( const std::string & name, size_t chan )
{
osmosdr::gain_range_t range;
if( name == "LNA" ) {
range = _lna_range;
} else if( name == "VGA1" ) {
range = _vga1_range;
} else if( name == "VGA2" ) {
range = _vga2_range;
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"requested an invalid gain element " + name );
}
return range;
return bladerf_common::get_gain_range(name, chan);
}
bool bladerf_source_c::set_gain_mode( bool automatic, size_t chan )
{
/* TODO: Implement AGC in the FPGA */
return false;
return bladerf_common::set_gain_mode(automatic, chan);
}
bool bladerf_source_c::get_gain_mode( size_t chan )
{
/* TODO: Read back AGC mode */
return false;
return bladerf_common::get_gain_mode(chan);
}
double bladerf_source_c::set_gain( double gain, size_t chan )
{
/* TODO: This is an overall system gain that has to be set */
return set_gain( gain, "LNA", chan ); /* we use only LNA here for now */
return bladerf_common::set_gain(gain, chan);
}
double bladerf_source_c::set_gain( double gain, const std::string & name, size_t chan)
{
int ret = 0;
if( name == "LNA" ) {
bladerf_lna_gain g;
if ( gain >= 6.0f )
g = BLADERF_LNA_GAIN_MAX;
else if ( gain >= 3.0f )
g = BLADERF_LNA_GAIN_MID;
else /* gain < 3.0f */
g = BLADERF_LNA_GAIN_BYPASS;
ret = bladerf_set_lna_gain( _dev.get(), g );
} else if( name == "VGA1" ) {
ret = bladerf_set_rxvga1( _dev.get(), (int)gain );
} else if( name == "VGA2" ) {
ret = bladerf_set_rxvga2( _dev.get(), (int)gain );
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"requested to set the gain "
"of an unknown gain element " + name );
}
/* Check for errors */
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"could not set " + name + " gain: " +
std::string(bladerf_strerror(ret)) );
}
return get_gain( name, chan );
return bladerf_common::set_gain(gain, name, chan);
}
double bladerf_source_c::get_gain( size_t chan )
{
/* TODO: This is an overall system gain that has to be set */
return get_gain( "LNA", chan ); /* we use only LNA here for now */
return bladerf_common::get_gain(chan);
}
double bladerf_source_c::get_gain( const std::string & name, size_t chan )
{
int g;
int ret = 0;
if( name == "LNA" ) {
bladerf_lna_gain lna_g;
ret = bladerf_get_lna_gain( _dev.get(), &lna_g );
g = lna_g == BLADERF_LNA_GAIN_BYPASS ? 0 : lna_g == BLADERF_LNA_GAIN_MID ? 3 : 6;
} else if( name == "VGA1" ) {
ret = bladerf_get_rxvga1( _dev.get(), &g );
} else if( name == "VGA2" ) {
ret = bladerf_get_rxvga2( _dev.get(), &g );
} else {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"requested to get the gain "
"of an unknown gain element " + name );
}
/* Check for errors */
if( ret ) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"could not get " + name + " gain: " +
std::string(bladerf_strerror(ret)) );
}
return (double)g;
return bladerf_common::get_gain(name, chan);
}
double bladerf_source_c::set_bb_gain( double gain, size_t chan )
{
osmosdr::gain_range_t vga1_gains = get_gain_range( "VGA1", chan );
osmosdr::gain_range_t vga2_gains = get_gain_range( "VGA2", chan );
// Gain partitioning from:
// http://www.limemicro.com/download/FAQ_v1.0r10.pdf part 5.18
// So: first maximize VGA1 gain, then VGA2
if ( gain > vga1_gains.stop() + vga2_gains.start() )
{
double clip_gain = vga2_gains.clip( gain - vga1_gains.stop(), true );
gain = set_gain(vga1_gains.stop(), "VGA1", chan) + set_gain(clip_gain, "VGA2", chan);
}
else
{
double clip_gain = vga1_gains.clip( gain - vga2_gains.start(), true );
gain = set_gain(clip_gain , "VGA1", chan) + set_gain(vga2_gains.start(), "VGA2", chan);
}
return gain;
return bladerf_common::set_bb_gain(gain, chan);
}
std::vector< std::string > bladerf_source_c::get_antennas( size_t chan )

View File

@ -84,6 +84,7 @@ public:
osmosdr::freq_range_t get_freq_range(size_t chan = 0);
double set_center_freq(double freq, size_t chan = 0);
double get_center_freq(size_t chan = 0);
double set_freq_corr( double ppm, size_t chan = 0 );
double get_freq_corr( size_t chan = 0 );
@ -118,7 +119,6 @@ public:
std::vector<std::string> get_clock_sources(const size_t mboard);
private:
osmosdr::gain_range_t _lna_range;
};
#endif /* INCLUDED_BLADERF_SOURCE_C_H */