diff options
author | Dimitri Stolnikov <horiz0n@gmx.net> | 2013-09-20 21:41:15 +0200 |
---|---|---|
committer | Dimitri Stolnikov <horiz0n@gmx.net> | 2013-09-28 00:07:49 +0200 |
commit | ba7188727c4862474d8584a564882cb276dc5e37 (patch) | |
tree | eb2698ee1c9fdfd97e31598bce642921b63ba7e4 /lib/bladerf/bladerf_sink_c.cc | |
parent | 04b4c8b66add671c08a880843880515a78d4f033 (diff) |
bladerf: migration to async api (WIP)
receive works, transmit locks up in work() after few seconds
Diffstat (limited to 'lib/bladerf/bladerf_sink_c.cc')
-rw-r--r-- | lib/bladerf/bladerf_sink_c.cc | 264 |
1 files changed, 142 insertions, 122 deletions
diff --git a/lib/bladerf/bladerf_sink_c.cc b/lib/bladerf/bladerf_sink_c.cc index fe63ce8..2cd59f7 100644 --- a/lib/bladerf/bladerf_sink_c.cc +++ b/lib/bladerf/bladerf_sink_c.cc @@ -95,73 +95,83 @@ bladerf_sink_c::bladerf_sink_c (const std::string &args) device_name = boost::str(boost::format( "libusb:instance=%d" ) % device_number); /* 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "failed to open bladeRF device " + device_name ); } - if (dict.count("fpga")) + if (dict.count("fw")) { - std::string fpga = dict["fpga"]; + std::string fw = dict["fw"]; - std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl; - ret = bladerf_load_fpga( this->dev, fpga.c_str() ); + 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_load_fpga has returned with " << ret << std::endl; + std::cerr << "bladerf_flash_firmware has failed with " << ret << std::endl; else - std::cerr << "The FPGA bitstream has been successfully loaded." << std::endl; + std::cerr << "The firmware has been successfully flashed." << std::endl; } - if (dict.count("fw")) + if (dict.count("fpga")) { - std::string fw = dict["fw"]; + std::string fpga = dict["fpga"]; - 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; + std::cerr << "Loading FPGA bitstream " << fpga << "..." << std::endl; + ret = bladerf_load_fpga( _dev, fpga.c_str() ); + if ( ret != 0 && ret != 1 ) + std::cerr << "bladerf_load_fpga 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 << "The FPGA bitstream has been successfully loaded." << std::endl; } std::cerr << "Using nuand LLC bladeRF #" << device_number; - char serial[33]; - if ( bladerf_get_serial( this->dev, serial ) == 0 ) + char serial[BLADERF_SERIAL_LENGTH]; + if ( bladerf_get_serial( _dev, serial ) == 0 ) std::cerr << " SN " << serial; 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; - 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 << 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! " - << "Use the device argument fpga=/path/to/the/bitstream.rbf to load it." - << std::endl; + std::ostringstream oss; + oss << "The FPGA is not configured! " + << "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] */ - 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] */ - this->vga2_range = osmosdr::gain_range_t( 0, 25, 1 ); + _vga2_range = osmosdr::gain_range_t( 0, 25, 1 ); + + _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 ) + std::cerr << "bladerf_init_stream has failed with " << ret << std::endl; - ret = bladerf_enable_module(this->dev, BLADERF_MODULE_TX, true); + ret = bladerf_enable_module( _dev, BLADERF_MODULE_TX, true ); 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; - this->thread = gr::thread::thread(write_task_dispatch, this); + _thread = gr::thread::thread( boost::bind(&bladerf_sink_c::write_task, this) ); } /* @@ -171,78 +181,89 @@ bladerf_sink_c::~bladerf_sink_c () { int ret; - this->set_running(false); - this->thread.join(); + set_running(false); + _thread.join(); - ret = bladerf_enable_module(this->dev, BLADERF_MODULE_TX, false); + ret = bladerf_enable_module( _dev, BLADERF_MODULE_TX, false ); 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 */ - 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 ); } -void bladerf_sink_c::write_task() +/* Convert & push samples to the sample fifo */ +void *bladerf_sink_c::stream_task( void *samples, size_t num_samples ) { - int i, n_samples_avail, n_samples; - int16_t *p; - gr_complex sample; + size_t i, n_avail; + void *ret; - while ( this->is_running() ) - { + ret = _buffers[_buf_index]; + _buf_index = (_buf_index + 1) % _num_buffers; + while ( is_running() ) + { { /* Lock the circular buffer */ - boost::unique_lock<boost::mutex> lock(this->sample_fifo_lock); + boost::unique_lock<boost::mutex> lock(_fifo_lock); /* Check to make sure we have samples available */ - n_samples_avail = this->sample_fifo->size(); - while( n_samples_avail < BLADERF_SAMPLE_BLOCK_SIZE ) { + n_avail = _fifo->size(); + while( n_avail < num_samples ) { /* Wait until there is at least a block size of samples ready */ - this->samples_available.wait(lock); - n_samples_avail = this->sample_fifo->size(); + _samp_avail.wait(lock); + n_avail = _fifo->size(); } /* Pop samples from circular buffer, write samples to outgoing buffer */ - 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(); + 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 ...*/ + } /* 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; - } - } - } - + //std::cerr << "-" << std::flush; + _samp_avail.notify_one(); } + + return ret; +} + +void bladerf_sink_c::write_task() +{ + int status; + + set_running( true ); + + /* Start stream and stay there until we kill the stream */ + status = bladerf_stream(_stream, BLADERF_MODULE_TX); + + if (status < 0) + std::cerr << "Sink stream error: " << bladerf_strerror(status) << std::endl; + + set_running( false ); } int bladerf_sink_c::work( int noutput_items, @@ -252,44 +273,43 @@ int bladerf_sink_c::work( int noutput_items, int n_space_avail, to_copy, limit, i; const gr_complex *in = (const gr_complex *) input_items[0]; - if ( ! this->is_running() ) + if ( ! is_running() ) return WORK_DONE; - if( noutput_items >= 0 ) { - /* Total samples we want to process */ - to_copy = noutput_items; + /* Total samples we want to process */ + to_copy = noutput_items; - /* While there are still samples to copy out ... */ - while( to_copy > 0 ) { - { - /* Acquire the circular buffer lock */ - boost::unique_lock<boost::mutex> lock(this->sample_fifo_lock); + /* While there are still samples to copy out ... */ + while( to_copy > 0 ) { + { + /* Acquire the circular buffer lock */ + boost::unique_lock<boost::mutex> lock(_fifo_lock); - /* Check to see how much space is available */ - n_space_avail = this->sample_fifo->capacity() - this->sample_fifo->size(); + /* Check to see how much space is available */ + n_space_avail = _fifo->capacity() - _fifo->size(); - while (n_space_avail == 0) { - this->samples_available.wait(lock); - n_space_avail = this->sample_fifo->capacity() - this->sample_fifo->size(); - } + while (n_space_avail == 0) { + _samp_avail.wait(lock); + n_space_avail = _fifo->capacity() - _fifo->size(); + } - /* Limit ourselves to either the number of output items ... - ... or whatever space is available */ - limit = (n_space_avail < noutput_items ? n_space_avail : noutput_items); + /* Limit ourselves to either the number of output items ... + ... or whatever space is available */ + limit = (n_space_avail < noutput_items ? n_space_avail : noutput_items); - /* Consume! */ - for( i = 0; i < limit; i++ ) { - this->sample_fifo->push_back(*in++); - } + /* Consume! */ + for( i = 0; i < limit; i++ ) { + _fifo->push_back(*in++); + } - /* Decrement the amount we need to copy */ - to_copy -= limit; + /* Decrement the amount we need to copy */ + to_copy -= limit; - } /* Unlock by leaving the scope */ + } /* Unlock by leaving the scope */ - /* Notify that we've just added some samples */ - this->samples_available.notify_one(); - } + /* Notify that we've just added some samples */ + //std::cerr << "+" << std::flush; + _samp_avail.notify_one(); } return noutput_items; @@ -308,7 +328,7 @@ size_t bladerf_sink_c::get_num_channels() 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) @@ -320,7 +340,7 @@ double bladerf_sink_c::set_sample_rate(double rate) /* Check to see if the sample rate is an integer */ 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "has failed to set integer rate, error " + @@ -328,7 +348,7 @@ double bladerf_sink_c::set_sample_rate(double rate) } } else { /* 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "has failed to set fractional rate, error " + @@ -344,7 +364,7 @@ double bladerf_sink_c::get_sample_rate() int ret; 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "has failed to get sample rate, error " + @@ -356,7 +376,7 @@ double bladerf_sink_c::get_sample_rate() 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 ) @@ -368,7 +388,7 @@ double bladerf_sink_c::set_center_freq( double freq, size_t chan ) freq > get_freq_range( chan ).stop() ) { std::cerr << "Failed to set out of bound frequency: " << freq << std::endl; } 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "failed to set center frequency " + @@ -386,7 +406,7 @@ double bladerf_sink_c::get_center_freq( size_t chan ) uint32_t freq; int ret; - ret = bladerf_get_frequency( this->dev, BLADERF_MODULE_TX, &freq ); + ret = bladerf_get_frequency( _dev, BLADERF_MODULE_TX, &freq ); if( ret ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "failed to get center frequency, error " + @@ -429,9 +449,9 @@ osmosdr::gain_range_t bladerf_sink_c::get_gain_range( const std::string & name, osmosdr::gain_range_t range; if( name == "VGA1" ) { - range = this->vga1_range; + range = _vga1_range; } else if( name == "VGA2" ) { - range = this->vga2_range; + range = _vga2_range; } else { throw std::runtime_error( std::string(__FUNCTION__) + " " + "requested an invalid gain element " + name ); @@ -460,9 +480,9 @@ double bladerf_sink_c::set_gain( double gain, const std::string & name, size_t c int ret = 0; if( name == "VGA1" ) { - ret = bladerf_set_txvga1( this->dev, (int)gain ); + ret = bladerf_set_txvga1( _dev, (int)gain ); } else if( name == "VGA2" ) { - ret = bladerf_set_txvga2( this->dev, (int)gain ); + ret = bladerf_set_txvga2( _dev, (int)gain ); } else { throw std::runtime_error( std::string(__FUNCTION__) + " " + "requested to set the gain " @@ -490,9 +510,9 @@ double bladerf_sink_c::get_gain( const std::string & name, size_t chan ) int ret = 0; if( name == "VGA1" ) { - ret = bladerf_get_txvga1( this->dev, &g ); + ret = bladerf_get_txvga1( _dev, &g ); } else if( name == "VGA2" ) { - ret = bladerf_get_txvga2( this->dev, &g ); + ret = bladerf_get_txvga2( _dev, &g ); } else { throw std::runtime_error( std::string(__FUNCTION__) + " " + "requested to get the gain " @@ -545,14 +565,14 @@ double bladerf_sink_c::set_bandwidth( double bandwidth, size_t chan ) int ret; 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 ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "could not set bandwidth, error " + boost::lexical_cast<std::string>(ret) ); } - return this->get_bandwidth(); + return get_bandwidth(); } double bladerf_sink_c::get_bandwidth( size_t chan ) @@ -560,7 +580,7 @@ double bladerf_sink_c::get_bandwidth( size_t chan ) uint32_t bandwidth; int ret; - ret = bladerf_get_bandwidth( this->dev, BLADERF_MODULE_TX, &bandwidth ); + ret = bladerf_get_bandwidth( _dev, BLADERF_MODULE_TX, &bandwidth ); if( ret ) { throw std::runtime_error( std::string(__FUNCTION__) + " " + "could not get bandwidth, error " + @@ -572,5 +592,5 @@ double bladerf_sink_c::get_bandwidth( size_t chan ) osmosdr::freq_range_t bladerf_sink_c::get_bandwidth_range( size_t chan ) { - return this->filter_bandwidths(); + return filter_bandwidths(); } |