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:
parent
ac1d8ec02d
commit
43a00ae785
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
ret = bladerf_sync_tx(_dev.get(), static_cast<void *>(_conv_buf),
|
||||
noutput_items, NULL, _stream_timeout_ms);
|
||||
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: "
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue