forked from sdr/gr-osmosdr
bladerf: migration to async api (WIP)
receive works, transmit locks up in work() after few seconds
This commit is contained in:
parent
2e9828f120
commit
1c9a793a70
|
@ -43,18 +43,12 @@
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
|
||||||
bladerf_common::bladerf_common() : running(true)
|
bladerf_common::bladerf_common() :
|
||||||
|
_is_running(false)
|
||||||
{
|
{
|
||||||
const char *env_fifo_size;
|
const char *env_fifo_size;
|
||||||
size_t fifo_size;
|
size_t fifo_size;
|
||||||
|
|
||||||
/* 1 Sample = i,q (2 int16_t's) */
|
|
||||||
this->raw_sample_buf = new int16_t[2 * BLADERF_SAMPLE_BLOCK_SIZE];
|
|
||||||
if (!raw_sample_buf) {
|
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) +
|
|
||||||
" has failed to allocate a raw sample buffer!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
env_fifo_size = getenv(BLADERF_FIFO_SIZE_ENV);
|
env_fifo_size = getenv(BLADERF_FIFO_SIZE_ENV);
|
||||||
fifo_size = BLADERF_SAMPLE_FIFO_SIZE;
|
fifo_size = BLADERF_SAMPLE_FIFO_SIZE;
|
||||||
|
|
||||||
|
@ -75,16 +69,15 @@ bladerf_common::bladerf_common() : running(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->sample_fifo = new boost::circular_buffer<gr_complex>(fifo_size);
|
_fifo = new boost::circular_buffer<gr_complex>(fifo_size);
|
||||||
if (!this->sample_fifo)
|
if (!_fifo)
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) +
|
throw std::runtime_error( std::string(__FUNCTION__) +
|
||||||
" has failed to allocate a sample FIFO!" );
|
" has failed to allocate a sample FIFO!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
bladerf_common::~bladerf_common()
|
bladerf_common::~bladerf_common()
|
||||||
{
|
{
|
||||||
delete[] this->raw_sample_buf;
|
delete _fifo;
|
||||||
delete this->sample_fifo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osmosdr::freq_range_t bladerf_common::freq_range()
|
osmosdr::freq_range_t bladerf_common::freq_range()
|
||||||
|
@ -116,7 +109,7 @@ osmosdr::freq_range_t bladerf_common::filter_bandwidths()
|
||||||
2.75, 3, 3.5, 4.375, 5, 6, 7, 10, 14;
|
2.75, 3, 3.5, 4.375, 5, 6, 7, 10, 14;
|
||||||
|
|
||||||
BOOST_FOREACH( double half_bw, half_bandwidths )
|
BOOST_FOREACH( double half_bw, half_bandwidths )
|
||||||
bandwidths += osmosdr::range_t( half_bw * 2.e6 );
|
bandwidths += osmosdr::range_t( half_bw * 2e6 );
|
||||||
|
|
||||||
return bandwidths;
|
return bandwidths;
|
||||||
}
|
}
|
||||||
|
@ -129,9 +122,10 @@ std::vector< std::string > bladerf_common::devices()
|
||||||
|
|
||||||
n_devices = bladerf_get_device_list(&devices);
|
n_devices = bladerf_get_device_list(&devices);
|
||||||
|
|
||||||
if (n_devices > 0) {
|
if (n_devices > 0)
|
||||||
for (ssize_t i = 0; i < n_devices; i++) {
|
{
|
||||||
|
for (ssize_t i = 0; i < n_devices; i++)
|
||||||
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
std::string serial(devices[i].serial);
|
std::string serial(devices[i].serial);
|
||||||
|
|
||||||
|
@ -154,12 +148,14 @@ std::vector< std::string > bladerf_common::devices()
|
||||||
|
|
||||||
bool bladerf_common::is_running()
|
bool bladerf_common::is_running()
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(this->state_lock);
|
boost::shared_lock<boost::shared_mutex> lock(_state_lock);
|
||||||
return this->running;
|
|
||||||
|
return _is_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_common::set_running(bool is_running)
|
void bladerf_common::set_running( bool is_running )
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::shared_mutex> lock(this->state_lock);
|
boost::unique_lock<boost::shared_mutex> lock(_state_lock);
|
||||||
this->running = is_running;
|
|
||||||
|
_is_running = is_running;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <boost/thread/condition_variable.hpp>
|
#include <boost/thread/condition_variable.hpp>
|
||||||
|
|
||||||
#include <gr_complex.h>
|
#include <gr_complex.h>
|
||||||
|
#include <gruel/thread.h>
|
||||||
|
|
||||||
#include <libbladeRF.h>
|
#include <libbladeRF.h>
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ class bladerf_common
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bladerf_common();
|
bladerf_common();
|
||||||
~bladerf_common();
|
virtual ~bladerf_common();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
osmosdr::freq_range_t freq_range();
|
osmosdr::freq_range_t freq_range();
|
||||||
|
@ -64,15 +65,24 @@ protected:
|
||||||
bool is_running();
|
bool is_running();
|
||||||
void set_running(bool is_running);
|
void set_running(bool is_running);
|
||||||
|
|
||||||
bladerf *dev;
|
bladerf *_dev;
|
||||||
|
|
||||||
int16_t *raw_sample_buf;
|
void **_buffers;
|
||||||
boost::circular_buffer<gr_complex> *sample_fifo;
|
struct bladerf_stream *_stream;
|
||||||
boost::mutex sample_fifo_lock;
|
size_t _num_buffers;
|
||||||
boost::condition_variable samples_available;
|
size_t _buf_index;
|
||||||
|
|
||||||
|
gruel::thread _thread;
|
||||||
|
|
||||||
|
boost::circular_buffer<gr_complex> *_fifo;
|
||||||
|
boost::mutex _fifo_lock;
|
||||||
|
boost::condition_variable _samp_avail;
|
||||||
|
|
||||||
|
osmosdr::gain_range_t _vga1_range;
|
||||||
|
osmosdr::gain_range_t _vga2_range;
|
||||||
private:
|
private:
|
||||||
bool running;
|
bool _is_running;
|
||||||
boost::shared_mutex state_lock;
|
boost::shared_mutex _state_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -96,73 +96,83 @@ bladerf_sink_c::bladerf_sink_c (const std::string &args)
|
||||||
device_name = boost::str(boost::format( "libusb:instance=%d" ) % device_number);
|
device_name = boost::str(boost::format( "libusb:instance=%d" ) % device_number);
|
||||||
|
|
||||||
/* Open a handle to the device */
|
/* Open a handle to the device */
|
||||||
ret = bladerf_open( &this->dev, device_name.c_str() );
|
ret = bladerf_open( &_dev, device_name.c_str() );
|
||||||
if ( ret != 0 ) {
|
if ( ret != 0 ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to open bladeRF device " + device_name );
|
"failed to open bladeRF device " + device_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dict.count("fw"))
|
||||||
|
{
|
||||||
|
std::string fw = dict["fw"];
|
||||||
|
|
||||||
|
std::cerr << "Flashing firmware image " << fw << "..., DO NOT INTERRUPT!"
|
||||||
|
<< std::endl;
|
||||||
|
ret = bladerf_flash_firmware( _dev, fw.c_str() );
|
||||||
|
if ( ret != 0 )
|
||||||
|
std::cerr << "bladerf_flash_firmware has failed with " << ret << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << "The firmware has been successfully flashed." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (dict.count("fpga"))
|
if (dict.count("fpga"))
|
||||||
{
|
{
|
||||||
std::string fpga = dict["fpga"];
|
std::string fpga = dict["fpga"];
|
||||||
|
|
||||||
std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl;
|
std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl;
|
||||||
ret = bladerf_load_fpga( this->dev, fpga.c_str() );
|
ret = bladerf_load_fpga( _dev, fpga.c_str() );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 && ret != 1 )
|
||||||
std::cerr << "bladerf_load_fpga has returned with " << ret << std::endl;
|
std::cerr << "bladerf_load_fpga has failed with " << ret << std::endl;
|
||||||
else
|
else
|
||||||
std::cerr << "The FPGA bitstream has been successfully loaded." << std::endl;
|
std::cerr << "The FPGA bitstream has been successfully loaded." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dict.count("fw"))
|
|
||||||
{
|
|
||||||
std::string fw = dict["fw"];
|
|
||||||
|
|
||||||
std::cerr << "Flashing firmware image " << fw << "..., "
|
|
||||||
<< "DO NOT INTERRUPT!"
|
|
||||||
<< std::endl;
|
|
||||||
ret = bladerf_flash_firmware( this->dev, fw.c_str() );
|
|
||||||
if ( ret != 0 )
|
|
||||||
std::cerr << "bladerf_flash_firmware has failed with " << ret << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << "The firmare has been successfully flashed, "
|
|
||||||
<< "please power cycle the bladeRF before using it."
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Using nuand LLC bladeRF #" << device_number;
|
std::cerr << "Using nuand LLC bladeRF #" << device_number;
|
||||||
|
|
||||||
char serial[33];
|
char serial[BLADERF_SERIAL_LENGTH];
|
||||||
if ( bladerf_get_serial( this->dev, serial ) == 0 )
|
if ( bladerf_get_serial( _dev, serial ) == 0 )
|
||||||
std::cerr << " SN " << serial;
|
std::cerr << " SN " << serial;
|
||||||
|
|
||||||
unsigned int major, minor;
|
unsigned int major, minor;
|
||||||
if ( bladerf_get_fw_version( this->dev, &major, &minor) == 0 )
|
if ( bladerf_get_fw_version( _dev, &major, &minor) == 0 )
|
||||||
std::cerr << " FW v" << major << "." << minor;
|
std::cerr << " FW v" << major << "." << minor;
|
||||||
|
|
||||||
if ( bladerf_get_fpga_version( this->dev, &major, &minor) == 0 )
|
if ( bladerf_get_fpga_version( _dev, &major, &minor) == 0 )
|
||||||
std::cerr << " FPGA v" << major << "." << minor;
|
std::cerr << " FPGA v" << major << "." << minor;
|
||||||
|
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
|
|
||||||
if ( bladerf_is_fpga_configured( this->dev ) != 1 )
|
if ( bladerf_is_fpga_configured( _dev ) != 1 )
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: The FPGA is not configured! "
|
std::ostringstream oss;
|
||||||
<< "Use the device argument fpga=/path/to/the/bitstream.rbf to load it."
|
oss << "The FPGA is not configured! "
|
||||||
<< std::endl;
|
<< "Provide device argument fpga=/path/to/the/bitstream.rbf to load it.";
|
||||||
|
|
||||||
|
throw std::runtime_error( oss.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the range of VGA1, VGA1GAINT[7:0] */
|
/* Set the range of VGA1, VGA1GAINT[7:0] */
|
||||||
this->vga1_range = osmosdr::gain_range_t( -35, -4, 1 );
|
_vga1_range = osmosdr::gain_range_t( -35, -4, 1 );
|
||||||
|
|
||||||
/* Set the range of VGA2, VGA2GAIN[4:0] */
|
/* Set the range of VGA2, VGA2GAIN[4:0] */
|
||||||
this->vga2_range = osmosdr::gain_range_t( 0, 25, 1 );
|
_vga2_range = osmosdr::gain_range_t( 0, 25, 1 );
|
||||||
|
|
||||||
ret = bladerf_enable_module(this->dev, BLADERF_MODULE_TX, true);
|
_buf_index = 0;
|
||||||
|
_num_buffers = 8; /* TODO: make it an argument */
|
||||||
|
const size_t samp_per_buf = 1024 * 10; /* TODO: make it an argument */
|
||||||
|
|
||||||
|
/* Initialize the stream */
|
||||||
|
ret = bladerf_init_stream( &_stream, _dev, stream_callback,
|
||||||
|
&_buffers, _num_buffers, BLADERF_FORMAT_SC16_Q12,
|
||||||
|
samp_per_buf, _num_buffers, this );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "bladerf_enable_module has returned with " << ret << std::endl;
|
std::cerr << "bladerf_init_stream has failed with " << ret << std::endl;
|
||||||
|
|
||||||
this->thread = gruel::thread(write_task_dispatch, this);
|
ret = bladerf_enable_module( _dev, BLADERF_MODULE_TX, true );
|
||||||
|
if ( ret != 0 )
|
||||||
|
std::cerr << "bladerf_enable_module has failed with " << ret << std::endl;
|
||||||
|
|
||||||
|
_thread = gruel::thread( boost::bind(&bladerf_sink_c::write_task, this) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -172,78 +182,89 @@ bladerf_sink_c::~bladerf_sink_c ()
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
this->set_running(false);
|
set_running(false);
|
||||||
this->thread.join();
|
_thread.join();
|
||||||
|
|
||||||
ret = bladerf_enable_module(this->dev, BLADERF_MODULE_TX, false);
|
ret = bladerf_enable_module( _dev, BLADERF_MODULE_TX, false );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "bladerf_enable_module has returned with " << ret << std::endl;
|
std::cerr << "bladerf_enable_module has failed with " << ret << std::endl;
|
||||||
|
|
||||||
|
/* Release stream resources */
|
||||||
|
bladerf_deinit_stream(_stream);
|
||||||
|
|
||||||
/* Close the device */
|
/* Close the device */
|
||||||
bladerf_close( this->dev );
|
bladerf_close( _dev );
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_sink_c::write_task_dispatch(bladerf_sink_c *obj)
|
void *bladerf_sink_c::stream_callback( struct bladerf *dev,
|
||||||
|
struct bladerf_stream *stream,
|
||||||
|
struct bladerf_metadata *metadata,
|
||||||
|
void *samples,
|
||||||
|
size_t num_samples,
|
||||||
|
void *user_data )
|
||||||
{
|
{
|
||||||
obj->write_task();
|
bladerf_sink_c *obj = (bladerf_sink_c *) user_data;
|
||||||
|
|
||||||
|
if ( ! obj->is_running() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return obj->stream_task( samples, num_samples );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert & push samples to the sample fifo */
|
||||||
|
void *bladerf_sink_c::stream_task( void *samples, size_t num_samples )
|
||||||
|
{
|
||||||
|
size_t i, n_avail;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
ret = _buffers[_buf_index];
|
||||||
|
_buf_index = (_buf_index + 1) % _num_buffers;
|
||||||
|
|
||||||
|
while ( is_running() )
|
||||||
|
{
|
||||||
|
{
|
||||||
|
/* Lock the circular buffer */
|
||||||
|
boost::unique_lock<boost::mutex> lock(_fifo_lock);
|
||||||
|
|
||||||
|
/* Check to make sure we have samples available */
|
||||||
|
n_avail = _fifo->size();
|
||||||
|
while( n_avail < num_samples ) {
|
||||||
|
/* Wait until there is at least a block size of samples ready */
|
||||||
|
_samp_avail.wait(lock);
|
||||||
|
n_avail = _fifo->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pop samples from circular buffer, write samples to outgoing buffer */
|
||||||
|
int16_t *p = (int16_t *) ret;
|
||||||
|
for( i = 0; i < num_samples; ++i ) {
|
||||||
|
gr_complex sample = _fifo->at(0);
|
||||||
|
_fifo->pop_front();
|
||||||
|
*p++ = 0xa000 | (int16_t)(real(sample)*2000);
|
||||||
|
*p++ = 0x5000 | (int16_t)(imag(sample)*2000);
|
||||||
|
}
|
||||||
|
} /* Give up the lock by leaving the scope ... */
|
||||||
|
|
||||||
|
/* Notify that we've just popped some samples */
|
||||||
|
//std::cerr << "-" << std::flush;
|
||||||
|
_samp_avail.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_sink_c::write_task()
|
void bladerf_sink_c::write_task()
|
||||||
{
|
{
|
||||||
int i, n_samples_avail, n_samples;
|
int status;
|
||||||
int16_t *p;
|
|
||||||
gr_complex sample;
|
|
||||||
|
|
||||||
while ( this->is_running() )
|
set_running( true );
|
||||||
{
|
|
||||||
|
|
||||||
{
|
/* Start stream and stay there until we kill the stream */
|
||||||
/* Lock the circular buffer */
|
status = bladerf_stream(_stream, BLADERF_MODULE_TX);
|
||||||
boost::unique_lock<boost::mutex> lock(this->sample_fifo_lock);
|
|
||||||
|
|
||||||
/* Check to make sure we have samples available */
|
if (status < 0)
|
||||||
n_samples_avail = this->sample_fifo->size();
|
std::cerr << "Sink stream error: " << bladerf_strerror(status) << std::endl;
|
||||||
while( n_samples_avail < BLADERF_SAMPLE_BLOCK_SIZE ) {
|
|
||||||
/* Wait until there is at least a block size of samples ready */
|
|
||||||
this->samples_available.wait(lock);
|
|
||||||
n_samples_avail = this->sample_fifo->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pop samples from circular buffer, write samples to outgoing buffer */
|
set_running( false );
|
||||||
int16_t *p = this->raw_sample_buf;
|
|
||||||
for( i = 0; i < BLADERF_SAMPLE_BLOCK_SIZE; ++i ) {
|
|
||||||
sample = this->sample_fifo->at(0);
|
|
||||||
this->sample_fifo->pop_front();
|
|
||||||
*p++ = 0xa000 | (int16_t)(real(sample)*2000);
|
|
||||||
*p++ = 0x5000 | (int16_t)(imag(sample)*2000);
|
|
||||||
}
|
|
||||||
} /* Give up the lock by leaving the scope ...*/
|
|
||||||
|
|
||||||
/* Notify that we've just popped some samples */
|
|
||||||
this->samples_available.notify_one();
|
|
||||||
|
|
||||||
/* Samples are available to write out */
|
|
||||||
n_samples = bladerf_tx(this->dev, BLADERF_FORMAT_SC16_Q12, this->raw_sample_buf,
|
|
||||||
BLADERF_SAMPLE_BLOCK_SIZE, NULL);
|
|
||||||
|
|
||||||
/* Check n_samples return value */
|
|
||||||
if( n_samples < 0 ) {
|
|
||||||
std::cerr << "Failed to write samples: "
|
|
||||||
<< bladerf_strerror(n_samples) << std::endl;
|
|
||||||
this->set_running(false);
|
|
||||||
} else {
|
|
||||||
if(n_samples != BLADERF_SAMPLE_BLOCK_SIZE) {
|
|
||||||
if(n_samples > BLADERF_SAMPLE_BLOCK_SIZE) {
|
|
||||||
std::cerr << "Warning: sent bloated sample block of "
|
|
||||||
<< n_samples << " samples!" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Warning: sent truncated sample block of "
|
|
||||||
<< n_samples << " samples!" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bladerf_sink_c::work( int noutput_items,
|
int bladerf_sink_c::work( int noutput_items,
|
||||||
|
@ -253,44 +274,43 @@ int bladerf_sink_c::work( int noutput_items,
|
||||||
int n_space_avail, to_copy, limit, i;
|
int n_space_avail, to_copy, limit, i;
|
||||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
const gr_complex *in = (const gr_complex *) input_items[0];
|
||||||
|
|
||||||
if ( ! this->is_running() )
|
if ( ! is_running() )
|
||||||
return WORK_DONE;
|
return WORK_DONE;
|
||||||
|
|
||||||
if( noutput_items >= 0 ) {
|
/* Total samples we want to process */
|
||||||
/* Total samples we want to process */
|
to_copy = noutput_items;
|
||||||
to_copy = noutput_items;
|
|
||||||
|
|
||||||
/* While there are still samples to copy out ... */
|
/* While there are still samples to copy out ... */
|
||||||
while( to_copy > 0 ) {
|
while( to_copy > 0 ) {
|
||||||
{
|
{
|
||||||
/* Acquire the circular buffer lock */
|
/* Acquire the circular buffer lock */
|
||||||
boost::unique_lock<boost::mutex> lock(this->sample_fifo_lock);
|
boost::unique_lock<boost::mutex> lock(_fifo_lock);
|
||||||
|
|
||||||
/* Check to see how much space is available */
|
/* Check to see how much space is available */
|
||||||
n_space_avail = this->sample_fifo->capacity() - this->sample_fifo->size();
|
n_space_avail = _fifo->capacity() - _fifo->size();
|
||||||
|
|
||||||
while (n_space_avail == 0) {
|
while (n_space_avail == 0) {
|
||||||
this->samples_available.wait(lock);
|
_samp_avail.wait(lock);
|
||||||
n_space_avail = this->sample_fifo->capacity() - this->sample_fifo->size();
|
n_space_avail = _fifo->capacity() - _fifo->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Limit ourselves to either the number of output items ...
|
/* Limit ourselves to either the number of output items ...
|
||||||
... or whatever space is available */
|
... or whatever space is available */
|
||||||
limit = (n_space_avail < noutput_items ? n_space_avail : noutput_items);
|
limit = (n_space_avail < noutput_items ? n_space_avail : noutput_items);
|
||||||
|
|
||||||
/* Consume! */
|
/* Consume! */
|
||||||
for( i = 0; i < limit; i++ ) {
|
for( i = 0; i < limit; i++ ) {
|
||||||
this->sample_fifo->push_back(*in++);
|
_fifo->push_back(*in++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decrement the amount we need to copy */
|
/* Decrement the amount we need to copy */
|
||||||
to_copy -= limit;
|
to_copy -= limit;
|
||||||
|
|
||||||
} /* Unlock by leaving the scope */
|
} /* Unlock by leaving the scope */
|
||||||
|
|
||||||
/* Notify that we've just added some samples */
|
/* Notify that we've just added some samples */
|
||||||
this->samples_available.notify_one();
|
//std::cerr << "+" << std::flush;
|
||||||
}
|
_samp_avail.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
return noutput_items;
|
return noutput_items;
|
||||||
|
@ -309,7 +329,7 @@ size_t bladerf_sink_c::get_num_channels()
|
||||||
|
|
||||||
osmosdr::meta_range_t bladerf_sink_c::get_sample_rates()
|
osmosdr::meta_range_t bladerf_sink_c::get_sample_rates()
|
||||||
{
|
{
|
||||||
return this->sample_rates();
|
return sample_rates();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_sink_c::set_sample_rate(double rate)
|
double bladerf_sink_c::set_sample_rate(double rate)
|
||||||
|
@ -321,7 +341,7 @@ double bladerf_sink_c::set_sample_rate(double rate)
|
||||||
/* Check to see if the sample rate is an integer */
|
/* Check to see if the sample rate is an integer */
|
||||||
if( (uint32_t)round(rate) == (uint32_t)rate )
|
if( (uint32_t)round(rate) == (uint32_t)rate )
|
||||||
{
|
{
|
||||||
ret = bladerf_set_sample_rate( this->dev, BLADERF_MODULE_TX, (uint32_t)rate, &actual );
|
ret = bladerf_set_sample_rate( _dev, BLADERF_MODULE_TX, (uint32_t)rate, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to set integer rate, error " +
|
"has failed to set integer rate, error " +
|
||||||
|
@ -329,7 +349,7 @@ double bladerf_sink_c::set_sample_rate(double rate)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Fractional sample rate */
|
/* TODO: Fractional sample rate */
|
||||||
ret = bladerf_set_sample_rate( this->dev, BLADERF_MODULE_TX, (uint32_t)rate, &actual );
|
ret = bladerf_set_sample_rate( _dev, BLADERF_MODULE_TX, (uint32_t)rate, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to set fractional rate, error " +
|
"has failed to set fractional rate, error " +
|
||||||
|
@ -345,7 +365,7 @@ double bladerf_sink_c::get_sample_rate()
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int rate = 0;
|
unsigned int rate = 0;
|
||||||
|
|
||||||
ret = bladerf_get_sample_rate( this->dev, BLADERF_MODULE_TX, &rate );
|
ret = bladerf_get_sample_rate( _dev, BLADERF_MODULE_TX, &rate );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to get sample rate, error " +
|
"has failed to get sample rate, error " +
|
||||||
|
@ -357,7 +377,7 @@ double bladerf_sink_c::get_sample_rate()
|
||||||
|
|
||||||
osmosdr::freq_range_t bladerf_sink_c::get_freq_range( size_t chan )
|
osmosdr::freq_range_t bladerf_sink_c::get_freq_range( size_t chan )
|
||||||
{
|
{
|
||||||
return this->freq_range();
|
return freq_range();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_sink_c::set_center_freq( double freq, size_t chan )
|
double bladerf_sink_c::set_center_freq( double freq, size_t chan )
|
||||||
|
@ -369,7 +389,7 @@ double bladerf_sink_c::set_center_freq( double freq, size_t chan )
|
||||||
freq > get_freq_range( chan ).stop() ) {
|
freq > get_freq_range( chan ).stop() ) {
|
||||||
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
|
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
|
||||||
} else {
|
} else {
|
||||||
ret = bladerf_set_frequency( this->dev, BLADERF_MODULE_TX, (uint32_t)freq );
|
ret = bladerf_set_frequency( _dev, BLADERF_MODULE_TX, (uint32_t)freq );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to set center frequency " +
|
"failed to set center frequency " +
|
||||||
|
@ -387,7 +407,7 @@ double bladerf_sink_c::get_center_freq( size_t chan )
|
||||||
uint32_t freq;
|
uint32_t freq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bladerf_get_frequency( this->dev, BLADERF_MODULE_TX, &freq );
|
ret = bladerf_get_frequency( _dev, BLADERF_MODULE_TX, &freq );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to get center frequency, error " +
|
"failed to get center frequency, error " +
|
||||||
|
@ -430,9 +450,9 @@ osmosdr::gain_range_t bladerf_sink_c::get_gain_range( const std::string & name,
|
||||||
osmosdr::gain_range_t range;
|
osmosdr::gain_range_t range;
|
||||||
|
|
||||||
if( name == "VGA1" ) {
|
if( name == "VGA1" ) {
|
||||||
range = this->vga1_range;
|
range = _vga1_range;
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
range = this->vga2_range;
|
range = _vga2_range;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested an invalid gain element " + name );
|
"requested an invalid gain element " + name );
|
||||||
|
@ -461,9 +481,9 @@ double bladerf_sink_c::set_gain( double gain, const std::string & name, size_t c
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if( name == "VGA1" ) {
|
if( name == "VGA1" ) {
|
||||||
ret = bladerf_set_txvga1( this->dev, (int)gain );
|
ret = bladerf_set_txvga1( _dev, (int)gain );
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
ret = bladerf_set_txvga2( this->dev, (int)gain );
|
ret = bladerf_set_txvga2( _dev, (int)gain );
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested to set the gain "
|
"requested to set the gain "
|
||||||
|
@ -491,9 +511,9 @@ double bladerf_sink_c::get_gain( const std::string & name, size_t chan )
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if( name == "VGA1" ) {
|
if( name == "VGA1" ) {
|
||||||
ret = bladerf_get_txvga1( this->dev, &g );
|
ret = bladerf_get_txvga1( _dev, &g );
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
ret = bladerf_get_txvga2( this->dev, &g );
|
ret = bladerf_get_txvga2( _dev, &g );
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested to get the gain "
|
"requested to get the gain "
|
||||||
|
@ -546,14 +566,14 @@ double bladerf_sink_c::set_bandwidth( double bandwidth, size_t chan )
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t actual;
|
uint32_t actual;
|
||||||
|
|
||||||
ret = bladerf_set_bandwidth( this->dev, BLADERF_MODULE_TX, (uint32_t)bandwidth, &actual );
|
ret = bladerf_set_bandwidth( _dev, BLADERF_MODULE_TX, (uint32_t)bandwidth, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"could not set bandwidth, error " +
|
"could not set bandwidth, error " +
|
||||||
boost::lexical_cast<std::string>(ret) );
|
boost::lexical_cast<std::string>(ret) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->get_bandwidth();
|
return get_bandwidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_sink_c::get_bandwidth( size_t chan )
|
double bladerf_sink_c::get_bandwidth( size_t chan )
|
||||||
|
@ -561,7 +581,7 @@ double bladerf_sink_c::get_bandwidth( size_t chan )
|
||||||
uint32_t bandwidth;
|
uint32_t bandwidth;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bladerf_get_bandwidth( this->dev, BLADERF_MODULE_TX, &bandwidth );
|
ret = bladerf_get_bandwidth( _dev, BLADERF_MODULE_TX, &bandwidth );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"could not get bandwidth, error " +
|
"could not get bandwidth, error " +
|
||||||
|
@ -573,5 +593,5 @@ double bladerf_sink_c::get_bandwidth( size_t chan )
|
||||||
|
|
||||||
osmosdr::freq_range_t bladerf_sink_c::get_bandwidth_range( size_t chan )
|
osmosdr::freq_range_t bladerf_sink_c::get_bandwidth_range( size_t chan )
|
||||||
{
|
{
|
||||||
return this->filter_bandwidths();
|
return filter_bandwidths();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
#include <gr_block.h>
|
#include <gr_block.h>
|
||||||
#include <gr_sync_block.h>
|
#include <gr_sync_block.h>
|
||||||
|
|
||||||
#include <libbladeRF.h>
|
|
||||||
|
|
||||||
#include "osmosdr/osmosdr_ranges.h"
|
#include "osmosdr/osmosdr_ranges.h"
|
||||||
#include "osmosdr_snk_iface.h"
|
#include "osmosdr_snk_iface.h"
|
||||||
|
|
||||||
#include "bladerf_common.h"
|
#include "bladerf_common.h"
|
||||||
|
|
||||||
class bladerf_sink_c;
|
class bladerf_sink_c;
|
||||||
|
@ -108,13 +107,20 @@ public:
|
||||||
double get_bandwidth( size_t chan = 0 );
|
double get_bandwidth( size_t chan = 0 );
|
||||||
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
||||||
|
|
||||||
private:
|
private: /* functions */
|
||||||
static void write_task_dispatch(bladerf_sink_c *obj);
|
static void *stream_callback( struct bladerf *_dev,
|
||||||
|
struct bladerf_stream *stream,
|
||||||
|
struct bladerf_metadata *metadata,
|
||||||
|
void *samples,
|
||||||
|
size_t num_samples,
|
||||||
|
void *user_data );
|
||||||
|
|
||||||
|
void *stream_task(void *samples, size_t num_samples);
|
||||||
|
|
||||||
void write_task();
|
void write_task();
|
||||||
|
|
||||||
gruel::thread thread;
|
private: /* members */
|
||||||
osmosdr::gain_range_t vga1_range;
|
|
||||||
osmosdr::gain_range_t vga2_range;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDED_BLADERF_SINK_C_H */
|
#endif /* INCLUDED_BLADERF_SINK_C_H */
|
||||||
|
|
|
@ -96,83 +96,72 @@ bladerf_source_c::bladerf_source_c (const std::string &args)
|
||||||
device_name = boost::str(boost::format( "libusb:instance=%d" ) % device_number);
|
device_name = boost::str(boost::format( "libusb:instance=%d" ) % device_number);
|
||||||
|
|
||||||
/* Open a handle to the device */
|
/* Open a handle to the device */
|
||||||
ret = bladerf_open( &this->dev, NULL );
|
ret = bladerf_open( &_dev, device_name.c_str() );
|
||||||
if ( ret != 0 ) {
|
if ( ret != 0 ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to open bladeRF device " + device_name );
|
"failed to open bladeRF device " + device_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dict.count("fw"))
|
||||||
|
{
|
||||||
|
std::string fw = dict["fw"];
|
||||||
|
|
||||||
|
std::cerr << "Flashing firmware image " << fw << "..., DO NOT INTERRUPT!"
|
||||||
|
<< std::endl;
|
||||||
|
ret = bladerf_flash_firmware( _dev, fw.c_str() );
|
||||||
|
if ( ret != 0 )
|
||||||
|
std::cerr << "bladerf_flash_firmware has failed with " << ret << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << "The firmware has been successfully flashed." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (dict.count("fpga"))
|
if (dict.count("fpga"))
|
||||||
{
|
{
|
||||||
std::string fpga = dict["fpga"];
|
std::string fpga = dict["fpga"];
|
||||||
|
|
||||||
std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl;
|
std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl;
|
||||||
ret = bladerf_load_fpga( this->dev, fpga.c_str() );
|
ret = bladerf_load_fpga( _dev, fpga.c_str() );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 && ret != 1 )
|
||||||
std::cerr << "bladerf_load_fpga has returned with " << ret << std::endl;
|
std::cerr << "bladerf_load_fpga has failed with " << ret << std::endl;
|
||||||
else
|
else
|
||||||
std::cerr << "The FPGA bitstream has been successfully loaded." << std::endl;
|
std::cerr << "The FPGA bitstream has been successfully loaded." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dict.count("fw"))
|
|
||||||
{
|
|
||||||
std::string fw = dict["fw"];
|
|
||||||
|
|
||||||
std::cerr << "Flashing firmware image " << fw << "..., "
|
|
||||||
<< "DO NOT INTERRUPT!"
|
|
||||||
<< std::endl;
|
|
||||||
ret = bladerf_flash_firmware( this->dev, fw.c_str() );
|
|
||||||
if ( ret != 0 )
|
|
||||||
std::cerr << "bladerf_flash_firmware has failed with " << ret << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << "The firmare has been successfully flashed, "
|
|
||||||
<< "please power cycle the bladeRF before using it."
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Using nuand LLC bladeRF #" << device_number;
|
std::cerr << "Using nuand LLC bladeRF #" << device_number;
|
||||||
|
|
||||||
char serial[33];
|
char serial[BLADERF_SERIAL_LENGTH];
|
||||||
if ( bladerf_get_serial( this->dev, serial ) == 0 )
|
if ( bladerf_get_serial( _dev, serial ) == 0 )
|
||||||
std::cerr << " SN " << serial;
|
std::cerr << " SN " << serial;
|
||||||
|
|
||||||
unsigned int major, minor;
|
unsigned int major, minor;
|
||||||
if ( bladerf_get_fw_version( this->dev, &major, &minor) == 0 )
|
if ( bladerf_get_fw_version( _dev, &major, &minor) == 0 )
|
||||||
std::cerr << " FW v" << major << "." << minor;
|
std::cerr << " FW v" << major << "." << minor;
|
||||||
|
|
||||||
if ( bladerf_get_fpga_version( this->dev, &major, &minor) == 0 )
|
if ( bladerf_get_fpga_version( _dev, &major, &minor) == 0 )
|
||||||
std::cerr << " FPGA v" << major << "." << minor;
|
std::cerr << " FPGA v" << major << "." << minor;
|
||||||
|
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
|
|
||||||
if ( bladerf_is_fpga_configured( this->dev ) != 1 )
|
if ( bladerf_is_fpga_configured( _dev ) != 1 )
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: The FPGA is not configured! "
|
std::ostringstream oss;
|
||||||
<< "Use the device argument fpga=/path/to/the/bitstream.rbf to load it."
|
oss << "The FPGA is not configured! "
|
||||||
<< std::endl;
|
<< "Provide device argument fpga=/path/to/the/bitstream.rbf to load it.";
|
||||||
|
|
||||||
|
throw std::runtime_error( oss.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the range of LNA, G_LNA_RXFE[1:0] */
|
|
||||||
this->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 */
|
|
||||||
this->vga1_range = osmosdr::gain_range_t( 5, 30, 1 );
|
|
||||||
|
|
||||||
/* Set the range of VGA2 VGA2GAIN[4:0], not recommended to be used above 30dB */
|
|
||||||
this->vga2_range = osmosdr::gain_range_t( 0, 60, 3 );
|
|
||||||
|
|
||||||
if (dict.count("sampling"))
|
if (dict.count("sampling"))
|
||||||
{
|
{
|
||||||
std::string sampling = dict["sampling"];
|
std::string sampling = dict["sampling"];
|
||||||
|
|
||||||
std::cerr << "Setting bladerf sampling to " << sampling << std::endl;
|
std::cerr << "Setting bladerf sampling to " << sampling << std::endl;
|
||||||
if( sampling == "internal") {
|
if( sampling == "internal") {
|
||||||
ret = bladerf_set_sampling( this->dev, BLADERF_SAMPLING_INTERNAL );
|
ret = bladerf_set_sampling( _dev, BLADERF_SAMPLING_INTERNAL );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "Problem while setting sampling mode " << ret << std::endl;
|
std::cerr << "Problem while setting sampling mode " << ret << std::endl;
|
||||||
|
|
||||||
} else if( sampling == "external" ) {
|
} else if( sampling == "external" ) {
|
||||||
ret = bladerf_set_sampling( this->dev, BLADERF_SAMPLING_EXTERNAL );
|
ret = bladerf_set_sampling( _dev, BLADERF_SAMPLING_EXTERNAL );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "Problem while setting sampling mode " << ret << std::endl;
|
std::cerr << "Problem while setting sampling mode " << ret << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
@ -180,12 +169,31 @@ 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 );
|
||||||
|
|
||||||
ret = bladerf_enable_module(this->dev, BLADERF_MODULE_RX, true);
|
/* 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, 60, 3 );
|
||||||
|
|
||||||
|
_buf_index = 0;
|
||||||
|
_num_buffers = 8; /* TODO: make it an argument */
|
||||||
|
const size_t samp_per_buf = 1024 * 10; /* TODO: make it an argument */
|
||||||
|
|
||||||
|
/* Initialize the stream */
|
||||||
|
ret = bladerf_init_stream( &_stream, _dev, stream_callback,
|
||||||
|
&_buffers, _num_buffers, BLADERF_FORMAT_SC16_Q12,
|
||||||
|
samp_per_buf, _num_buffers, this );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "bladerf_enable_module has returned with " << ret << std::endl;
|
std::cerr << "bladerf_init_stream has failed with " << ret << std::endl;
|
||||||
|
|
||||||
this->thread = gruel::thread(read_task_dispatch, this);
|
ret = bladerf_enable_module( _dev, BLADERF_MODULE_RX, true );
|
||||||
|
if ( ret != 0 )
|
||||||
|
std::cerr << "bladerf_enable_module has failed with " << ret << std::endl;
|
||||||
|
|
||||||
|
_thread = gruel::thread( boost::bind(&bladerf_source_c::read_task, this) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -195,113 +203,121 @@ bladerf_source_c::~bladerf_source_c ()
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
this->set_running(false);
|
set_running(false);
|
||||||
this->thread.join();
|
_thread.join();
|
||||||
|
|
||||||
ret = bladerf_enable_module(this->dev, BLADERF_MODULE_RX, false);
|
ret = bladerf_enable_module( _dev, BLADERF_MODULE_RX, false );
|
||||||
if ( ret != 0 )
|
if ( ret != 0 )
|
||||||
std::cerr << "bladerf_enable_module has returned with " << ret << std::endl;
|
std::cerr << "bladerf_enable_module has failed with " << ret << std::endl;
|
||||||
|
|
||||||
|
/* Release stream resources */
|
||||||
|
bladerf_deinit_stream(_stream);
|
||||||
|
|
||||||
/* Close the device */
|
/* Close the device */
|
||||||
bladerf_close( this->dev );
|
bladerf_close( _dev );
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_source_c::read_task_dispatch(bladerf_source_c *obj)
|
void *bladerf_source_c::stream_callback( struct bladerf *dev,
|
||||||
|
struct bladerf_stream *stream,
|
||||||
|
struct bladerf_metadata *metadata,
|
||||||
|
void *samples,
|
||||||
|
size_t num_samples,
|
||||||
|
void *user_data )
|
||||||
{
|
{
|
||||||
obj->read_task();
|
bladerf_source_c *obj = (bladerf_source_c *) user_data;
|
||||||
|
|
||||||
|
if ( ! obj->is_running() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return obj->stream_task( samples, num_samples );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert & push samples to the sample fifo */
|
||||||
|
void *bladerf_source_c::stream_task( void *samples, size_t num_samples )
|
||||||
|
{
|
||||||
|
size_t i, n_avail, to_copy;
|
||||||
|
int16_t *sample = (int16_t *)samples;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
ret = _buffers[_buf_index];
|
||||||
|
_buf_index = (_buf_index + 1) % _num_buffers;
|
||||||
|
|
||||||
|
_fifo_lock.lock();
|
||||||
|
|
||||||
|
n_avail = _fifo->capacity() - _fifo->size();
|
||||||
|
to_copy = (n_avail < num_samples ? n_avail : num_samples);
|
||||||
|
|
||||||
|
for(i = 0; i < to_copy; i++ ) {
|
||||||
|
/* Mask valid bits only */
|
||||||
|
*(sample) &= 0xfff;
|
||||||
|
*(sample+1) &= 0xfff;
|
||||||
|
|
||||||
|
/* Sign extend the 12-bit IQ values, if needed */
|
||||||
|
if( (*sample) & 0x800 ) *(sample) |= 0xf000;
|
||||||
|
if( *(sample+1) & 0x800 ) *(sample+1) |= 0xf000;
|
||||||
|
|
||||||
|
/* Push sample to the fifo */
|
||||||
|
_fifo->push_back( gr_complex( *sample * (1.0f/2048.0f),
|
||||||
|
*(sample+1) * (1.0f/2048.0f) ) );
|
||||||
|
|
||||||
|
/* offset to the next I+Q sample */
|
||||||
|
sample += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fifo_lock.unlock();
|
||||||
|
|
||||||
|
/* We have made some new samples available to the consumer in work() */
|
||||||
|
if (to_copy) {
|
||||||
|
//std::cerr << "+" << std::flush;
|
||||||
|
_samp_avail.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indicate overrun, if neccesary */
|
||||||
|
if (to_copy < num_samples)
|
||||||
|
std::cerr << "O" << std::flush;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_source_c::read_task()
|
void bladerf_source_c::read_task()
|
||||||
{
|
{
|
||||||
int16_t si, sq, *next_val;
|
int status;
|
||||||
ssize_t n_samples;
|
|
||||||
size_t n_avail, to_copy;
|
|
||||||
|
|
||||||
while ( this->is_running() )
|
set_running( true );
|
||||||
{
|
|
||||||
|
|
||||||
n_samples = bladerf_rx(this->dev, BLADERF_FORMAT_SC16_Q12, this->raw_sample_buf,
|
/* Start stream and stay there until we kill the stream */
|
||||||
BLADERF_SAMPLE_BLOCK_SIZE, NULL);
|
status = bladerf_stream(_stream, BLADERF_MODULE_RX);
|
||||||
|
|
||||||
if (n_samples < 0) {
|
if (status < 0)
|
||||||
std::cerr << "Failed to read samples: "
|
std::cerr << "Source stream error: " << bladerf_strerror(status) << std::endl;
|
||||||
<< bladerf_strerror(n_samples) << std::endl;
|
|
||||||
this->set_running(false);
|
|
||||||
} else {
|
|
||||||
if (n_samples != BLADERF_SAMPLE_BLOCK_SIZE) {
|
|
||||||
if (n_samples > BLADERF_SAMPLE_BLOCK_SIZE) {
|
|
||||||
std::cerr << "Warning: received bloated sample block of "
|
|
||||||
<< n_samples << " bytes!"<< std::endl;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Warning: received truncated sample block of "
|
|
||||||
<< n_samples << " bytes!"<< std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
//std::cerr << "+" << std::flush;
|
set_running( false );
|
||||||
|
|
||||||
next_val = this->raw_sample_buf;
|
|
||||||
|
|
||||||
this->sample_fifo_lock.lock();
|
|
||||||
n_avail = this->sample_fifo->capacity() - this->sample_fifo->size();
|
|
||||||
to_copy = (n_avail < (size_t)n_samples ? n_avail : (size_t)n_samples);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < to_copy; ++i) {
|
|
||||||
si = *next_val++ & 0xfff;
|
|
||||||
sq = *next_val++ & 0xfff;
|
|
||||||
|
|
||||||
/* Sign extend the 12-bit IQ values, if needed */
|
|
||||||
if( si & 0x800 ) si |= 0xf000;
|
|
||||||
if( sq & 0x800 ) sq |= 0xf000;
|
|
||||||
|
|
||||||
gr_complex sample((float)si * (1.0f/2048.0f),
|
|
||||||
(float)sq * (1.0f/2048.0f));
|
|
||||||
|
|
||||||
this->sample_fifo->push_back(sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->sample_fifo_lock.unlock();
|
|
||||||
|
|
||||||
/* We have made some new samples available to the consumer in work() */
|
|
||||||
if (to_copy) {
|
|
||||||
this->samples_available.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Indicate overrun, if neccesary */
|
|
||||||
if (to_copy < (size_t)n_samples) {
|
|
||||||
std::cerr << "O" << std::flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main work function, pull samples from the driver */
|
/* Main work function, pull samples from the sample fifo */
|
||||||
int bladerf_source_c::work( int noutput_items,
|
int bladerf_source_c::work( int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items )
|
gr_vector_void_star &output_items )
|
||||||
{
|
{
|
||||||
int n_samples_avail;
|
if ( ! is_running() )
|
||||||
|
|
||||||
if ( ! this->is_running() )
|
|
||||||
return WORK_DONE;
|
return WORK_DONE;
|
||||||
|
|
||||||
if( noutput_items >= 0 ) {
|
if( noutput_items > 0 ) {
|
||||||
gr_complex *out = (gr_complex *)output_items[0];
|
gr_complex *out = (gr_complex *)output_items[0];
|
||||||
boost::unique_lock<boost::mutex> lock(this->sample_fifo_lock);
|
|
||||||
|
boost::unique_lock<boost::mutex> lock(_fifo_lock);
|
||||||
|
|
||||||
/* Wait until we have the requested number of samples */
|
/* Wait until we have the requested number of samples */
|
||||||
n_samples_avail = this->sample_fifo->size();
|
int n_samples_avail = _fifo->size();
|
||||||
|
|
||||||
while (n_samples_avail < noutput_items) {
|
while (n_samples_avail < noutput_items) {
|
||||||
this->samples_available.wait(lock);
|
_samp_avail.wait(lock);
|
||||||
n_samples_avail = this->sample_fifo->size();
|
n_samples_avail = _fifo->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < noutput_items; ++i) {
|
for(int i = 0; i < noutput_items; ++i) {
|
||||||
out[i] = this->sample_fifo->at(0);
|
out[i] = _fifo->at(0);
|
||||||
this->sample_fifo->pop_front();
|
_fifo->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::cerr << "-" << std::flush;
|
//std::cerr << "-" << std::flush;
|
||||||
|
@ -323,7 +339,7 @@ size_t bladerf_source_c::get_num_channels()
|
||||||
|
|
||||||
osmosdr::meta_range_t bladerf_source_c::get_sample_rates()
|
osmosdr::meta_range_t bladerf_source_c::get_sample_rates()
|
||||||
{
|
{
|
||||||
return this->sample_rates();
|
return sample_rates();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_source_c::set_sample_rate( double rate )
|
double bladerf_source_c::set_sample_rate( double rate )
|
||||||
|
@ -335,7 +351,7 @@ double bladerf_source_c::set_sample_rate( double rate )
|
||||||
/* Check to see if the sample rate is an integer */
|
/* Check to see if the sample rate is an integer */
|
||||||
if( (uint32_t)round(rate) == (uint32_t)rate )
|
if( (uint32_t)round(rate) == (uint32_t)rate )
|
||||||
{
|
{
|
||||||
ret = bladerf_set_sample_rate( this->dev, BLADERF_MODULE_RX, (uint32_t)rate, &actual );
|
ret = bladerf_set_sample_rate( _dev, BLADERF_MODULE_RX, (uint32_t)rate, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to set integer rate, error " +
|
"has failed to set integer rate, error " +
|
||||||
|
@ -343,7 +359,7 @@ double bladerf_source_c::set_sample_rate( double rate )
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Fractional sample rate */
|
/* TODO: Fractional sample rate */
|
||||||
ret = bladerf_set_sample_rate( this->dev, BLADERF_MODULE_RX, (uint32_t)rate, &actual );
|
ret = bladerf_set_sample_rate( _dev, BLADERF_MODULE_RX, (uint32_t)rate, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to set fractional rate, error " +
|
"has failed to set fractional rate, error " +
|
||||||
|
@ -359,7 +375,7 @@ double bladerf_source_c::get_sample_rate()
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int rate = 0;
|
unsigned int rate = 0;
|
||||||
|
|
||||||
ret = bladerf_get_sample_rate( this->dev, BLADERF_MODULE_RX, &rate );
|
ret = bladerf_get_sample_rate( _dev, BLADERF_MODULE_RX, &rate );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"has failed to get sample rate, error " +
|
"has failed to get sample rate, error " +
|
||||||
|
@ -371,7 +387,7 @@ double bladerf_source_c::get_sample_rate()
|
||||||
|
|
||||||
osmosdr::freq_range_t bladerf_source_c::get_freq_range( size_t chan )
|
osmosdr::freq_range_t bladerf_source_c::get_freq_range( size_t chan )
|
||||||
{
|
{
|
||||||
return this->freq_range();
|
return freq_range();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_source_c::set_center_freq( double freq, size_t chan )
|
double bladerf_source_c::set_center_freq( double freq, size_t chan )
|
||||||
|
@ -383,7 +399,7 @@ double bladerf_source_c::set_center_freq( double freq, size_t chan )
|
||||||
freq > get_freq_range( chan ).stop() ) {
|
freq > get_freq_range( chan ).stop() ) {
|
||||||
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
|
std::cerr << "Failed to set out of bound frequency: " << freq << std::endl;
|
||||||
} else {
|
} else {
|
||||||
ret = bladerf_set_frequency( this->dev, BLADERF_MODULE_RX, (uint32_t)freq );
|
ret = bladerf_set_frequency( _dev, BLADERF_MODULE_RX, (uint32_t)freq );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to set center frequency " +
|
"failed to set center frequency " +
|
||||||
|
@ -401,7 +417,7 @@ double bladerf_source_c::get_center_freq( size_t chan )
|
||||||
uint32_t freq;
|
uint32_t freq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bladerf_get_frequency( this->dev, BLADERF_MODULE_RX, &freq );
|
ret = bladerf_get_frequency( _dev, BLADERF_MODULE_RX, &freq );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"failed to get center frequency, error " +
|
"failed to get center frequency, error " +
|
||||||
|
@ -444,11 +460,11 @@ osmosdr::gain_range_t bladerf_source_c::get_gain_range( const std::string & name
|
||||||
osmosdr::gain_range_t range;
|
osmosdr::gain_range_t range;
|
||||||
|
|
||||||
if( name == "LNA" ) {
|
if( name == "LNA" ) {
|
||||||
range = this->lna_range;
|
range = _lna_range;
|
||||||
} else if( name == "VGA1" ) {
|
} else if( name == "VGA1" ) {
|
||||||
range = this->vga1_range;
|
range = _vga1_range;
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
range = this->vga2_range;
|
range = _vga2_range;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested an invalid gain element " + name );
|
"requested an invalid gain element " + name );
|
||||||
|
@ -492,11 +508,11 @@ double bladerf_source_c::set_gain( double gain, const std::string & name, size_t
|
||||||
<< "setting to LNA_MAX (6dB)" << std::endl;
|
<< "setting to LNA_MAX (6dB)" << std::endl;
|
||||||
g = BLADERF_LNA_GAIN_MAX;
|
g = BLADERF_LNA_GAIN_MAX;
|
||||||
}
|
}
|
||||||
ret = bladerf_set_lna_gain( this->dev, g );
|
ret = bladerf_set_lna_gain( _dev, g );
|
||||||
} else if( name == "VGA1" ) {
|
} else if( name == "VGA1" ) {
|
||||||
ret = bladerf_set_rxvga1( this->dev, (int)gain );
|
ret = bladerf_set_rxvga1( _dev, (int)gain );
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
ret = bladerf_set_rxvga2( this->dev, (int)gain );
|
ret = bladerf_set_rxvga2( _dev, (int)gain );
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested to set the gain "
|
"requested to set the gain "
|
||||||
|
@ -526,12 +542,12 @@ double bladerf_source_c::get_gain( const std::string & name, size_t chan )
|
||||||
|
|
||||||
if( name == "LNA" ) {
|
if( name == "LNA" ) {
|
||||||
bladerf_lna_gain lna_g;
|
bladerf_lna_gain lna_g;
|
||||||
ret = bladerf_get_lna_gain( this->dev, &lna_g );
|
ret = bladerf_get_lna_gain( _dev, &lna_g );
|
||||||
g = lna_g == BLADERF_LNA_GAIN_BYPASS ? 0 : lna_g == BLADERF_LNA_GAIN_MID ? 3 : 6;
|
g = lna_g == BLADERF_LNA_GAIN_BYPASS ? 0 : lna_g == BLADERF_LNA_GAIN_MID ? 3 : 6;
|
||||||
} else if( name == "VGA1" ) {
|
} else if( name == "VGA1" ) {
|
||||||
ret = bladerf_get_rxvga1( this->dev, &g );
|
ret = bladerf_get_rxvga1( _dev, &g );
|
||||||
} else if( name == "VGA2" ) {
|
} else if( name == "VGA2" ) {
|
||||||
ret = bladerf_get_rxvga2( this->dev, &g );
|
ret = bladerf_get_rxvga2( _dev, &g );
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"requested to get the gain "
|
"requested to get the gain "
|
||||||
|
@ -584,14 +600,14 @@ double bladerf_source_c::set_bandwidth( double bandwidth, size_t chan )
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t actual;
|
uint32_t actual;
|
||||||
|
|
||||||
ret = bladerf_set_bandwidth( this->dev, BLADERF_MODULE_RX, (uint32_t)bandwidth, &actual );
|
ret = bladerf_set_bandwidth( _dev, BLADERF_MODULE_RX, (uint32_t)bandwidth, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"could not set bandwidth, error " +
|
"could not set bandwidth, error " +
|
||||||
boost::lexical_cast<std::string>(ret) );
|
boost::lexical_cast<std::string>(ret) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->get_bandwidth();
|
return get_bandwidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_source_c::get_bandwidth( size_t chan )
|
double bladerf_source_c::get_bandwidth( size_t chan )
|
||||||
|
@ -599,7 +615,7 @@ double bladerf_source_c::get_bandwidth( size_t chan )
|
||||||
uint32_t bandwidth;
|
uint32_t bandwidth;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bladerf_get_bandwidth( this->dev, BLADERF_MODULE_RX, &bandwidth );
|
ret = bladerf_get_bandwidth( _dev, BLADERF_MODULE_RX, &bandwidth );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"could not get bandwidth, error " +
|
"could not get bandwidth, error " +
|
||||||
|
@ -611,5 +627,5 @@ double bladerf_source_c::get_bandwidth( size_t chan )
|
||||||
|
|
||||||
osmosdr::freq_range_t bladerf_source_c::get_bandwidth_range( size_t chan )
|
osmosdr::freq_range_t bladerf_source_c::get_bandwidth_range( size_t chan )
|
||||||
{
|
{
|
||||||
return this->filter_bandwidths();
|
return filter_bandwidths();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
#include <gr_block.h>
|
#include <gr_block.h>
|
||||||
#include <gr_sync_block.h>
|
#include <gr_sync_block.h>
|
||||||
|
|
||||||
#include <libbladeRF.h>
|
|
||||||
|
|
||||||
#include "osmosdr/osmosdr_ranges.h"
|
#include "osmosdr/osmosdr_ranges.h"
|
||||||
#include "osmosdr_src_iface.h"
|
#include "osmosdr_src_iface.h"
|
||||||
|
|
||||||
#include "bladerf_common.h"
|
#include "bladerf_common.h"
|
||||||
|
|
||||||
class bladerf_source_c;
|
class bladerf_source_c;
|
||||||
|
@ -108,14 +107,20 @@ public:
|
||||||
double get_bandwidth( size_t chan = 0 );
|
double get_bandwidth( size_t chan = 0 );
|
||||||
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
||||||
|
|
||||||
private:
|
private: /* functions */
|
||||||
static void read_task_dispatch(bladerf_source_c *obj);
|
static void *stream_callback( struct bladerf *_dev,
|
||||||
|
struct bladerf_stream *stream,
|
||||||
|
struct bladerf_metadata *metadata,
|
||||||
|
void *samples,
|
||||||
|
size_t num_samples,
|
||||||
|
void *user_data );
|
||||||
|
|
||||||
|
void *stream_task(void *samples, size_t num_samples);
|
||||||
|
|
||||||
void read_task();
|
void read_task();
|
||||||
|
|
||||||
gruel::thread thread;
|
private: /* members */
|
||||||
osmosdr::gain_range_t lna_range;
|
osmosdr::gain_range_t _lna_range;
|
||||||
osmosdr::gain_range_t vga1_range;
|
|
||||||
osmosdr::gain_range_t vga2_range;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDED_BLADERF_SOURCE_C_H */
|
#endif /* INCLUDED_BLADERF_SOURCE_C_H */
|
||||||
|
|
Loading…
Reference in New Issue