diff --git a/lib/bladerf/bladerf_common.cc b/lib/bladerf/bladerf_common.cc index 094de3e..191a327 100644 --- a/lib/bladerf/bladerf_common.cc +++ b/lib/bladerf/bladerf_common.cc @@ -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() diff --git a/lib/bladerf/bladerf_common.h b/lib/bladerf/bladerf_common.h index d16c02f..b791003 100644 --- a/lib/bladerf/bladerf_common.h +++ b/lib/bladerf/bladerf_common.h @@ -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; diff --git a/lib/bladerf/bladerf_sink_c.cc b/lib/bladerf/bladerf_sink_c.cc index 2dc2e04..fffe8dd 100644 --- a/lib/bladerf/bladerf_sink_c.cc +++ b/lib/bladerf/bladerf_sink_c.cc @@ -35,10 +35,19 @@ #include #include +#include +#include #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 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(_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(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(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(&_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(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(&_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(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(_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(_conv_buf), + noutput_items, NULL, _stream_timeout_ms); + } if ( ret != 0 ) { std::cerr << _pfx << "bladerf_sync_tx error: " diff --git a/lib/bladerf/bladerf_sink_c.h b/lib/bladerf/bladerf_sink_c.h index 6b2cb00..57d174b 100644 --- a/lib/bladerf/bladerf_sink_c.h +++ b/lib/bladerf/bladerf_sink_c.h @@ -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(); diff --git a/lib/bladerf/bladerf_source_c.cc b/lib/bladerf/bladerf_source_c.cc index 7450b1b..b4afcb2 100644 --- a/lib/bladerf/bladerf_source_c.cc +++ b/lib/bladerf/bladerf_source_c.cc @@ -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(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(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(_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;