bladeRF: Added SOB/EOB stream tag handling support to bladerf_sink

When running with metadata mode enabled, the bladerf_sink supports 'tx_sob' and
'tx_eob' stream tags. Anything not in the burst will be dropped, and a warning
will be printed.

Use of the bladeRF metadata can be enabled via a 'enable_metadata'
device argument. If running full-duplex, this must be provided to both
the source and the sink. This does not currently any additional features
to the sink.
This commit is contained in:
Jon Szymaniak 2015-06-22 17:38:03 -04:00 committed by Dimitri Stolnikov
parent ac1d8ec02d
commit 43a00ae785
5 changed files with 179 additions and 6 deletions

View File

@ -190,8 +190,15 @@ void bladerf_common::set_verbosity(const std::string &verbosity)
bool bladerf_common::start(bladerf_module module)
{
int ret;
bladerf_format format;
ret = bladerf_sync_config(_dev.get(), module, BLADERF_FORMAT_SC16_Q11,
if (_use_metadata) {
format = BLADERF_FORMAT_SC16_Q11_META;
} else {
format = BLADERF_FORMAT_SC16_Q11;
}
ret = bladerf_sync_config(_dev.get(), module, format,
_num_buffers, _samples_per_buffer,
_num_transfers, _stream_timeout_ms);
@ -382,6 +389,8 @@ void bladerf_common::init(dict_t &dict, bladerf_module module)
_stream_timeout_ms = boost::lexical_cast< unsigned int >(dict["stream_timeout_ms"] );
}
_use_metadata = dict.count("enable_metadata") != 0;
/* Require value to be >= 2 so we can ensure we have twice as many
* buffers as transfers */
if (_num_buffers <= 1) {
@ -429,7 +438,7 @@ void bladerf_common::init(dict_t &dict, bladerf_module module)
osmosdr::freq_range_t bladerf_common::freq_range()
{
/* assuming the same for RX & TX */
return osmosdr::freq_range_t( _xb_200_attached ? 0 : 300e6, 3.8e9 );
return osmosdr::freq_range_t( _xb_200_attached ? 0 : 280e6, BLADERF_FREQUENCY_MAX );
}
osmosdr::meta_range_t bladerf_common::sample_rates()

View File

@ -83,6 +83,8 @@ protected:
int16_t *_conv_buf;
int _conv_buf_size; /* In units of samples */
bool _use_metadata;
osmosdr::gain_range_t _vga1_range;
osmosdr::gain_range_t _vga2_range;

View File

@ -35,10 +35,19 @@
#include <boost/lexical_cast.hpp>
#include <gnuradio/io_signature.h>
#include <gnuradio/tags.h>
#include <gnuradio/sync_block.h>
#include "arg_helpers.h"
#include "bladerf_sink_c.h"
//#define DEBUG_BLADERF_SINK
#ifdef DEBUG_BLADERF_SINK
# define DBG(input) std::cerr << _pfx << input << std::endl
#else
# define DBG(input)
#endif
using namespace boost::assign;
/*
@ -82,10 +91,12 @@ bladerf_sink_c::bladerf_sink_c (const std::string &args)
/* Set the range of VGA2, VGA2GAIN[4:0] */
_vga2_range = osmosdr::gain_range_t( 0, 25, 1 );
}
bool bladerf_sink_c::start()
{
_in_burst = false;
return bladerf_common::start(BLADERF_MODULE_TX);
}
@ -94,6 +105,136 @@ bool bladerf_sink_c::stop()
return bladerf_common::stop(BLADERF_MODULE_TX);
}
#define INVALID_IDX -1
int bladerf_sink_c::transmit_with_tags(int noutput_items)
{
int count = 0;
int status = 0;
// For a long burst, we may be transmitting the burst contents over
// multiple work calls, so we'll just be sending the entire buffer
// Therefore, we initialize our indicies for this case.
int start_idx = 0;
int end_idx = (noutput_items - 1);
struct bladerf_metadata meta;
std::vector<gr::tag_t> tags;
int16_t zeros[8] = { 0 };
memset(&meta, 0, sizeof(meta));
DBG("transmit_with_tags(" << noutput_items << ")");
// Important Note: We assume that these tags are ordered by their offsets.
// This is true for GNU Radio 3.7.7.x, since the GR runtime libs store
// these in a multimap.
//
// If you're using an earlier GNU Radio version, you may have to sort
// the tags vector.
get_tags_in_window(tags, 0, 0, noutput_items);
if (tags.size() == 0) {
if (_in_burst) {
DBG("TX'ing " << noutput_items << " samples in within a burst...");
return bladerf_sync_tx(_dev.get(),
static_cast<void *>(_conv_buf),
noutput_items, &meta, _stream_timeout_ms);
} else {
std::cerr << _pfx << "Dropping " << noutput_items
<< " samples not in a burst." << std::endl;
}
}
BOOST_FOREACH( gr::tag_t tag, tags) {
// Upon seeing an SOB tag, update our offset. We'll TX the start of the
// burst when we see an EOB or at the end of this function - whichever
// occurs first.
if (pmt::symbol_to_string(tag.key) == "tx_sob") {
if (_in_burst) {
std::cerr << ("Got SOB while already within a burst");
return BLADERF_ERR_INVAL;
} else {
start_idx = static_cast<int>(tag.offset - nitems_read(0));
DBG("Got SOB " << start_idx << " samples into work payload");
meta.flags |= (BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_START);
_in_burst = true;
}
} else if (pmt::symbol_to_string(tag.key) == "tx_eob") {
if (!_in_burst) {
std::cerr << _pfx << "Got EOB while not in burst" << std::endl;
return BLADERF_ERR_INVAL;
}
// Upon seeing an EOB, transmit what we have and reset our state
end_idx = static_cast<int>(tag.offset - nitems_read(0));
DBG("Got EOB " << end_idx << " samples into work payload");
if ( (start_idx == INVALID_IDX) || (start_idx > end_idx) ) {
DBG("Buffer indicies are in an invalid state!");
return BLADERF_ERR_INVAL;
}
count = end_idx - start_idx + 1;
DBG("TXing @ EOB [" << start_idx << ":" << end_idx << "]");
status = bladerf_sync_tx(_dev.get(),
static_cast<void *>(&_conv_buf[2*start_idx]),
count, &meta, _stream_timeout_ms);
if (status != 0) {
return status;
}
/* TODO: libbladeRF should now take care of this for us,
* as of the libbladeRF version that includes the
* TX_UPDATE_TIMESTAMP flag. Verify this potentially remove this.
* (The meta.flags changes would then be applied to the previous
* bladerf_sync_tx() call.)
*/
DBG("TXing Zeros with burst end flag");
meta.flags &= ~(BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_START);
meta.flags |= BLADERF_META_FLAG_TX_BURST_END;
status = bladerf_sync_tx(_dev.get(),
static_cast<void *>(zeros),
4, &meta, _stream_timeout_ms);
/* Reset our state */
start_idx = INVALID_IDX;
end_idx = (noutput_items - 1);
meta.flags = 0;
_in_burst = false;
if (status != 0) {
DBG("Failed to send zero samples to flush EOB");
return status;
}
}
}
// We had a start of burst with no end yet - transmit those samples
if (_in_burst) {
count = end_idx - start_idx + 1;
DBG("TXing SOB [" << start_idx << ":" << end_idx << "]");
status = bladerf_sync_tx(_dev.get(),
static_cast<void *>(&_conv_buf[2*start_idx]),
count, &meta, _stream_timeout_ms);
}
return status;
}
int bladerf_sink_c::work( int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items )
@ -110,6 +251,8 @@ int bladerf_sink_c::work( int noutput_items,
if (tmp == NULL) {
throw std::runtime_error( std::string(__FUNCTION__) +
"Failed to realloc _conv_buf" );
} else {
DBG("Resized _conv_buf to " << _conv_buf_size << " samples");
}
_conv_buf = static_cast<int16_t*>(tmp);
@ -121,9 +264,12 @@ int bladerf_sink_c::work( int noutput_items,
_conv_buf[i++] = (int16_t)(scaling * imag(*in++));
}
/* Submit them to the device */
if (_use_metadata) {
ret = transmit_with_tags(noutput_items);
} else {
ret = bladerf_sync_tx(_dev.get(), static_cast<void *>(_conv_buf),
noutput_items, NULL, _stream_timeout_ms);
}
if ( ret != 0 ) {
std::cerr << _pfx << "bladerf_sync_tx error: "

View File

@ -65,6 +65,14 @@ private:
bladerf_sink_c (const std::string & args); // private constructor
// Transmit converted samples stored in _conv_buf, applying SOB and EOB
// based upon the provided tags
//
// Returns bladeRF error code
int transmit_with_tags(int noutput_items);
bool _in_burst;
public:
bool start();
bool stop();

View File

@ -142,6 +142,8 @@ int bladerf_source_c::work( int noutput_items,
int16_t *current;
const float scaling = 1.0f / 2048.0f;
gr_complex *out = static_cast<gr_complex *>(output_items[0]);
struct bladerf_metadata meta;
struct bladerf_metadata *meta_ptr = NULL;
if (noutput_items > _conv_buf_size) {
void *tmp;
@ -156,9 +158,15 @@ int bladerf_source_c::work( int noutput_items,
_conv_buf = static_cast<int16_t*>(tmp);
}
if (_use_metadata) {
memset(&meta, 0, sizeof(meta));
meta.flags = BLADERF_META_FLAG_RX_NOW;
meta_ptr = &meta;
}
/* Grab all the samples into the temporary buffer */
ret = bladerf_sync_rx(_dev.get(), static_cast<void *>(_conv_buf),
noutput_items, NULL, _stream_timeout_ms);
noutput_items, meta_ptr, _stream_timeout_ms);
if ( ret != 0 ) {
std::cerr << _pfx << "bladerf_sync_rx error: "
<< bladerf_strerror(ret) << std::endl;