summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-uhd/grc/gen_uhd_usrp_blocks.py65
-rw-r--r--gr-uhd/include/gr_uhd_usrp_sink.h45
-rw-r--r--gr-uhd/include/gr_uhd_usrp_source.h43
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_sink.cc77
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_source.cc75
-rw-r--r--gr-uhd/swig/__init__.py14
6 files changed, 289 insertions, 30 deletions
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index 7116dad3b..19e64d2fd 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -27,8 +27,12 @@ MAIN_TMPL = """\
<import>from gnuradio import uhd</import>
<make>uhd.usrp_$(sourk)(
device_addr=\$dev_addr,
- io_type=uhd.io_type.\$type.type,
- num_channels=\$nchan,
+ stream_args=uhd.stream_args(
+ cpu_format='\$type.type',
+ otw_format='\$otw.format',
+ args='\$otw.args',
+ channels=range(\$nchan),
+ ),
)
\#if \$clock_rate()
self.\$(id).set_clock_rate(\$clock_rate, uhd.ALL_MBOARDS)
@@ -84,17 +88,66 @@ self.\$(id).set_bandwidth(\$bw$(n), $n)
<key>type</key>
<type>enum</type>
<option>
- <name>Complex</name>
+ <name>complex float32</name>
<key>complex</key>
- <opt>type:COMPLEX_FLOAT32</opt>
+ <opt>type:fc32</opt>
<opt>vlen:1</opt>
</option>
<option>
- <name>Short</name>
+ <name>complex uint16</name>
<key>short</key>
- <opt>type:COMPLEX_INT16</opt>
+ <opt>type:sc16</opt>
<opt>vlen:2</opt>
</option>
+ <option>
+ <name>real float32</name>
+ <key>float</key>
+ <opt>type:f32</opt>
+ <opt>vlen:1</opt>
+ </option>
+ <option>
+ <name>real uint16</name>
+ <key>short</key>
+ <opt>type:s16</opt>
+ <opt>vlen:1</opt>
+ </option>
+ </param>
+ <param>
+ <name>Wire Format</name>
+ <key>otw_format</key>
+ <type>enum</type>
+ <option>
+ <name>complex uint16</name>
+ <key>sc16</key>
+ <opt>format:sc16</opt>
+ <opt>args:</opt>
+ </option>
+ <option>
+ <name>complex uint8</name>
+ <key>sc8</key>
+ <opt>format:sc8</opt>
+ <opt>args:</opt>
+ </option>
+ <option>
+ <name>real uint16</name>
+ <opt>format:s16</opt>
+ <opt>args:</opt>
+ </option>
+ <option>
+ <name>real uint8</name>
+ <opt>format:s8</opt>
+ <opt>args:</opt>
+ </option>
+ <option>
+ <name>magnitude uint16</name>
+ <opt>format:s16</opt>
+ <opt>args:magnitude</opt>
+ </option>
+ <option>
+ <name>magnitude uint8</name>
+ <opt>format:s8</opt>
+ <opt>args:magnitude</opt>
+ </option>
</param>
<param>
<name>Device Addr</name>
diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h
index f11d00063..e3d21226a 100644
--- a/gr-uhd/include/gr_uhd_usrp_sink.h
+++ b/gr-uhd/include/gr_uhd_usrp_sink.h
@@ -26,6 +26,20 @@
#include <gr_sync_block.h>
#include <uhd/usrp/multi_usrp.hpp>
+#ifndef INCLUDED_UHD_STREAM_HPP
+namespace uhd{
+ struct GR_UHD_API stream_args_t{
+ std::string cpu_format;
+ std::string otw_format;
+ std::string args;
+ std::vector<size_t> channels;
+ };
+}
+# define INCLUDED_UHD_STREAM_HPP
+#else
+# define GR_UHD_USE_STREAM_API
+#endif
+
class uhd_usrp_sink;
/*!
@@ -62,6 +76,37 @@ GR_UHD_API boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink(
size_t num_channels
);
+/*!
+ * \brief Make a new USRP sink block.
+ *
+ * The USRP sink block reads a stream and transmits the samples.
+ * The sink block also provides API calls for transmitter settings.
+ *
+ * TX Stream tagging:
+ *
+ * The following tag keys will be consumed by the work function:
+ * - pmt::pmt_string_to_symbol("tx_sob")
+ * - pmt::pmt_string_to_symbol("tx_eob")
+ * - pmt::pmt_string_to_symbol("tx_time")
+ *
+ * The sob and eob (start and end of burst) tag values are pmt booleans.
+ * When present, burst tags should be set to true (pmt::PMT_T).
+ *
+ * The timstamp tag value is a pmt tuple of the following:
+ * (uint64 seconds, and double fractional seconds).
+ *
+ * See the UHD manual for more detailed documentation:
+ * http://code.ettus.com/redmine/ettus/projects/uhd/wiki
+ *
+ * \param device_addr the address to identify the hardware
+ * \param stream_args the IO format and channel specification
+ * \return a new USRP sink block object
+ */
+GR_UHD_API boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink(
+ const uhd::device_addr_t &device_addr,
+ const uhd::stream_args_t &stream_args
+);
+
class GR_UHD_API uhd_usrp_sink : virtual public gr_sync_block{
public:
diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h
index fecc6e94d..b194ba4a3 100644
--- a/gr-uhd/include/gr_uhd_usrp_source.h
+++ b/gr-uhd/include/gr_uhd_usrp_source.h
@@ -26,6 +26,20 @@
#include <gr_sync_block.h>
#include <uhd/usrp/multi_usrp.hpp>
+#ifndef INCLUDED_UHD_STREAM_HPP
+namespace uhd{
+ struct GR_UHD_API stream_args_t{
+ std::string cpu_format;
+ std::string otw_format;
+ std::string args;
+ std::vector<size_t> channels;
+ };
+}
+# define INCLUDED_UHD_STREAM_HPP
+#else
+# define GR_UHD_USE_STREAM_API
+#endif
+
class uhd_usrp_source;
/*!
@@ -55,7 +69,34 @@ class uhd_usrp_source;
GR_UHD_API boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source(
const uhd::device_addr_t &device_addr,
const uhd::io_type_t &io_type,
- size_t num_channels
+ size_t num_channels = 1
+);
+
+/*!
+ * \brief Make a new USRP source block.
+ *
+ * The USRP source block receives samples and writes to a stream.
+ * The source block also provides API calls for receiver settings.
+ *
+ * RX Stream tagging:
+ *
+ * The following tag keys will be produced by the work function:
+ * - pmt::pmt_string_to_symbol("rx_time")
+ *
+ * The timstamp tag value is a pmt tuple of the following:
+ * (uint64 seconds, and double fractional seconds).
+ * A timestamp tag is produced at start() and after overflows.
+ *
+ * See the UHD manual for more detailed documentation:
+ * http://code.ettus.com/redmine/ettus/projects/uhd/wiki
+ *
+ * \param device_addr the address to identify the hardware
+ * \param stream_args the IO format and channel specification
+ * \return a new USRP source block object
+ */
+GR_UHD_API boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source(
+ const uhd::device_addr_t &device_addr,
+ const uhd::stream_args_t &stream_args
);
class GR_UHD_API uhd_usrp_source : virtual public gr_sync_block{
diff --git a/gr-uhd/lib/gr_uhd_usrp_sink.cc b/gr-uhd/lib/gr_uhd_usrp_sink.cc
index 1a6595293..56b16dbc2 100644
--- a/gr-uhd/lib/gr_uhd_usrp_sink.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_sink.cc
@@ -22,11 +22,25 @@
#include <gr_uhd_usrp_sink.h>
#include <gr_io_signature.h>
#include <stdexcept>
+#include <boost/make_shared.hpp>
static const pmt::pmt_t SOB_KEY = pmt::pmt_string_to_symbol("tx_sob");
static const pmt::pmt_t EOB_KEY = pmt::pmt_string_to_symbol("tx_eob");
static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("tx_time");
+#include <uhd/convert.hpp>
+inline gr_io_signature_sptr args_to_io_sig(const uhd::stream_args_t &args){
+ const size_t nchan = std::max<size_t>(args.channels.size(), 1);
+ #ifdef GR_UHD_USE_STREAM_API
+ const size_t size = uhd::convert::get_bytes_per_item(args.cpu_format);
+ #else
+ size_t size = 0;
+ if (args.cpu_format == "fc32") size = 8;
+ if (args.cpu_format == "sc16") size = 4;
+ #endif
+ return gr_make_io_signature(nchan, nchan, size);
+}
+
/***********************************************************************
* UHD Multi USRP Sink Impl
**********************************************************************/
@@ -34,17 +48,18 @@ class uhd_usrp_sink_impl : public uhd_usrp_sink{
public:
uhd_usrp_sink_impl(
const uhd::device_addr_t &device_addr,
- const uhd::io_type_t &io_type,
- size_t num_channels
+ const uhd::stream_args_t &stream_args
):
gr_sync_block(
"gr uhd usrp sink",
- gr_make_io_signature(num_channels, num_channels, io_type.size),
+ args_to_io_sig(stream_args),
gr_make_io_signature(0, 0, 0)
),
- _type(io_type),
- _nchan(num_channels)
+ _stream_args(stream_args),
+ _nchan(stream_args.channels.size())
{
+ if (stream_args.cpu_format == "fc32") _type = boost::make_shared<uhd::io_type_t>(uhd::io_type_t::COMPLEX_FLOAT32);
+ if (stream_args.cpu_format == "sc16") _type = boost::make_shared<uhd::io_type_t>(uhd::io_type_t::COMPLEX_INT16);
_dev = uhd::usrp::multi_usrp::make(device_addr);
}
@@ -194,11 +209,17 @@ public:
get_tags_in_range(_tags, 0, samp0_count, samp0_count + ninput_items);
if (not _tags.empty()) this->tag_work(ninput_items);
+ #ifdef GR_UHD_USE_STREAM_API
//send all ninput_items with metadata
+ const size_t num_sent = _tx_stream->send(
+ input_items, ninput_items, _metadata, 1.0
+ );
+ #else
const size_t num_sent = _dev->get_device()->send(
input_items, ninput_items, _metadata,
- _type, uhd::device::SEND_MODE_FULL_BUFF, 1.0
+ *_type, uhd::device::SEND_MODE_FULL_BUFF, 1.0
);
+ #endif
//increment the timespec by the number of samples sent
_metadata.time_spec += uhd::time_spec_t(0, num_sent, _sample_rate);
@@ -266,15 +287,25 @@ public:
//Send an empty start-of-burst packet to begin streaming.
//Set at a time in the near future to avoid late packets.
bool start(void){
+ #ifdef GR_UHD_USE_STREAM_API
+ _tx_stream = _dev->get_tx_stream(_stream_args);
+ #endif
+
_metadata.start_of_burst = true;
_metadata.end_of_burst = false;
_metadata.has_time_spec = _nchan > 1;
_metadata.time_spec = get_time_now() + uhd::time_spec_t(0.01);
+ #ifdef GR_UHD_USE_STREAM_API
+ _tx_stream->send(
+ gr_vector_const_void_star(_nchan), 0, _metadata, 1.0
+ );
+ #else
_dev->get_device()->send(
gr_vector_const_void_star(_nchan), 0, _metadata,
- _type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
+ *_type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
);
+ #endif
return true;
}
@@ -285,16 +316,24 @@ public:
_metadata.end_of_burst = true;
_metadata.has_time_spec = false;
+ #ifdef GR_UHD_USE_STREAM_API
+ _tx_stream->send(gr_vector_const_void_star(_nchan), 0, _metadata, 1.0);
+ #else
_dev->get_device()->send(
gr_vector_const_void_star(_nchan), 0, _metadata,
- _type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
+ *_type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
);
+ #endif
return true;
}
private:
uhd::usrp::multi_usrp::sptr _dev;
- const uhd::io_type_t _type;
+ const uhd::stream_args_t _stream_args;
+ boost::shared_ptr<uhd::io_type_t> _type;
+ #ifdef GR_UHD_USE_STREAM_API
+ uhd::tx_streamer::sptr _tx_stream;
+ #endif
size_t _nchan;
uhd::tx_metadata_t _metadata;
double _sample_rate;
@@ -311,7 +350,25 @@ boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink(
const uhd::io_type_t &io_type,
size_t num_channels
){
+ //fill in the streamer args
+ uhd::stream_args_t stream_args;
+ switch(io_type.tid){
+ case uhd::io_type_t::COMPLEX_FLOAT32: stream_args.cpu_format = "fc32"; break;
+ case uhd::io_type_t::COMPLEX_INT16: stream_args.cpu_format = "sc16"; break;
+ default: throw std::runtime_error("only complex float and shorts known to work");
+ }
+ stream_args.otw_format = "sc16"; //only sc16 known to work
+ for (size_t chan = 0; chan < num_channels; chan++)
+ stream_args.channels.push_back(chan); //linear mapping
+
+ return uhd_make_usrp_sink(device_addr, stream_args);
+}
+
+boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink(
+ const uhd::device_addr_t &device_addr,
+ const uhd::stream_args_t &stream_args
+){
return boost::shared_ptr<uhd_usrp_sink>(
- new uhd_usrp_sink_impl(device_addr, io_type, num_channels)
+ new uhd_usrp_sink_impl(device_addr, stream_args)
);
}
diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc
index a3369ade0..12dd1bee7 100644
--- a/gr-uhd/lib/gr_uhd_usrp_source.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_source.cc
@@ -24,9 +24,23 @@
#include <stdexcept>
#include <iostream>
#include <boost/format.hpp>
+#include <boost/make_shared.hpp>
static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("rx_time");
+#include <uhd/convert.hpp>
+inline gr_io_signature_sptr args_to_io_sig(const uhd::stream_args_t &args){
+ const size_t nchan = std::max<size_t>(args.channels.size(), 1);
+ #ifdef GR_UHD_USE_STREAM_API
+ const size_t size = uhd::convert::get_bytes_per_item(args.cpu_format);
+ #else
+ size_t size = 0;
+ if (args.cpu_format == "fc32") size = 8;
+ if (args.cpu_format == "sc16") size = 4;
+ #endif
+ return gr_make_io_signature(nchan, nchan, size);
+}
+
/***********************************************************************
* UHD Multi USRP Source Impl
**********************************************************************/
@@ -34,19 +48,20 @@ class uhd_usrp_source_impl : public uhd_usrp_source{
public:
uhd_usrp_source_impl(
const uhd::device_addr_t &device_addr,
- const uhd::io_type_t &io_type,
- size_t num_channels
+ const uhd::stream_args_t &stream_args
):
gr_sync_block(
"gr uhd usrp source",
gr_make_io_signature(0, 0, 0),
- gr_make_io_signature(num_channels, num_channels, io_type.size)
+ args_to_io_sig(stream_args)
),
- _type(io_type),
- _nchan(num_channels),
+ _stream_args(stream_args),
+ _nchan(stream_args.channels.size()),
_stream_now(_nchan == 1),
_tag_now(false)
{
+ if (stream_args.cpu_format == "fc32") _type = boost::make_shared<uhd::io_type_t>(uhd::io_type_t::COMPLEX_FLOAT32);
+ if (stream_args.cpu_format == "sc16") _type = boost::make_shared<uhd::io_type_t>(uhd::io_type_t::COMPLEX_INT16);
std::stringstream str;
str << name() << unique_id();
_id = pmt::pmt_string_to_symbol(str.str());
@@ -187,22 +202,33 @@ public:
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
){
+ #ifdef GR_UHD_USE_STREAM_API
//In order to allow for low-latency:
//We receive all available packets without timeout.
//This call can timeout under regular operation...
- size_t num_samps = _dev->get_device()->recv(
- output_items, noutput_items, _metadata,
- _type, uhd::device::RECV_MODE_FULL_BUFF, 0.0
+ size_t num_samps = _rx_stream->recv(
+ output_items, noutput_items, _metadata, 0.0
);
//If receive resulted in a timeout condition:
//We now receive a single packet with a large timeout.
if (_metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT){
+ num_samps = _rx_stream->recv(
+ output_items, noutput_items, _metadata, 1.0
+ );
+ }
+ #else
+ size_t num_samps = _dev->get_device()->recv(
+ output_items, noutput_items, _metadata,
+ *_type, uhd::device::RECV_MODE_FULL_BUFF, 0.0
+ );
+ if (_metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT){
num_samps = _dev->get_device()->recv(
output_items, noutput_items, _metadata,
- _type, uhd::device::RECV_MODE_ONE_PACKET, 1.0
+ *_type, uhd::device::RECV_MODE_ONE_PACKET, 1.0
);
}
+ #endif
//handle possible errors conditions
switch(_metadata.error_code){
@@ -242,6 +268,10 @@ public:
}
bool start(void){
+ #ifdef GR_UHD_USE_STREAM_API
+ _rx_stream = _dev->get_rx_stream(_stream_args);
+ _samps_per_packet = _rx_stream->get_max_num_samps();
+ #endif
//setup a stream command that starts streaming slightly in the future
static const double reasonable_delay = 0.1; //order of magnitude over RTT
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
@@ -278,7 +308,12 @@ public:
private:
uhd::usrp::multi_usrp::sptr _dev;
- const uhd::io_type_t _type;
+ const uhd::stream_args_t _stream_args;
+ boost::shared_ptr<uhd::io_type_t> _type;
+ #ifdef GR_UHD_USE_STREAM_API
+ uhd::rx_streamer::sptr _rx_stream;
+ size_t _samps_per_packet;
+ #endif
size_t _nchan;
bool _stream_now, _tag_now;
uhd::rx_metadata_t _metadata;
@@ -294,7 +329,25 @@ boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source(
const uhd::io_type_t &io_type,
size_t num_channels
){
+ //fill in the streamer args
+ uhd::stream_args_t stream_args;
+ switch(io_type.tid){
+ case uhd::io_type_t::COMPLEX_FLOAT32: stream_args.cpu_format = "fc32"; break;
+ case uhd::io_type_t::COMPLEX_INT16: stream_args.cpu_format = "sc16"; break;
+ default: throw std::runtime_error("only complex float and shorts known to work");
+ }
+ stream_args.otw_format = "sc16"; //only sc16 known to work
+ for (size_t chan = 0; chan < num_channels; chan++)
+ stream_args.channels.push_back(chan); //linear mapping
+
+ return uhd_make_usrp_source(device_addr, stream_args);
+}
+
+boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source(
+ const uhd::device_addr_t &device_addr,
+ const uhd::stream_args_t &stream_args
+){
return boost::shared_ptr<uhd_usrp_source>(
- new uhd_usrp_source_impl(device_addr, io_type, num_channels)
+ new uhd_usrp_source_impl(device_addr, stream_args)
);
}
diff --git a/gr-uhd/swig/__init__.py b/gr-uhd/swig/__init__.py
index 7745b4b79..5c7642a81 100644
--- a/gr-uhd/swig/__init__.py
+++ b/gr-uhd/swig/__init__.py
@@ -57,6 +57,13 @@ def _prepare_uhd_swig():
def __setitem__(self, key, val): self.set(key, val)
setattr(uhd_swig, 'device_addr_t', device_addr_t)
+ #make the streamer args take **kwargs on init
+ class streamer_args(uhd_swig.stream_args_t):
+ def __init__(self, *args, **kwargs):
+ super(stream_args_t, self).__init__(*args)
+ for key, val in kwargs.iteritems(): setattr(self, key, val)
+ setattr(uhd_swig, 'stream_args_t', stream_args_t)
+
#handle general things on all uhd_swig attributes
#Install the __str__ and __repr__ handlers if applicable
#Create aliases for uhd swig attributes to avoid the "_t"
@@ -87,9 +94,12 @@ def _prepare_uhd_swig():
for index, key, cast in (
(0, 'device_addr', device_addr),
(1, 'io_type', io_type),
+ (1, 'stream_args', stream_args),
):
- if len(args) > index: args[index] = cast(args[index])
- if kwargs.has_key(key): kwargs[key] = cast(kwargs[key])
+ try:
+ if len(args) > index: args[index] = cast(args[index])
+ if kwargs.has_key(key): kwargs[key] = cast(kwargs[key])
+ except: pass
return old_constructor(*args, **kwargs)
return constructor_interceptor
setattr(uhd_swig, attr, constructor_factory(getattr(uhd_swig, attr)))