aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-03-02 22:07:17 -0800
committerJosh Blum <josh@joshknows.com>2010-03-02 22:07:17 -0800
commit4efafcc2e20b9a980800a979edf5ea7a493b6462 (patch)
tree49fbf3c6e5b25f31a0de30ecf11ceb19872e590f
parent13bd67b4949a91df5e6696e708c935266b14c502 (diff)
downloaduhd-4efafcc2e20b9a980800a979edf5ea7a493b6462.tar.gz
uhd-4efafcc2e20b9a980800a979edf5ea7a493b6462.tar.bz2
uhd-4efafcc2e20b9a980800a979edf5ea7a493b6462.zip
Expanded the UDP api:
We can make simple udp transports for discovery and control. We can support a udp zero copy transport (currently just asio). Reworked the io_impl for usrp2 to work with the zero copy api. So far, all of this untested other than compiling. A cut-down vrt library is in the works to simplify the io impl.
-rw-r--r--host/include/uhd/transport/CMakeLists.txt4
-rw-r--r--host/include/uhd/transport/smart_buffer.hpp45
-rw-r--r--host/include/uhd/transport/udp_simple.hpp (renamed from host/include/uhd/transport/udp.hpp)47
-rw-r--r--host/include/uhd/transport/udp_zero_copy.hpp76
-rw-r--r--host/include/uhd/usrp/usrp2.hpp10
-rw-r--r--host/lib/CMakeLists.txt9
-rw-r--r--host/lib/transport/udp.cpp98
-rw-r--r--host/lib/transport/udp_simple.cpp133
-rw-r--r--host/lib/transport/udp_zero_copy_none.cpp117
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp202
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp18
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp24
12 files changed, 523 insertions, 260 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index b786eb945..ba8b33cc5 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -17,6 +17,8 @@
INSTALL(FILES
- udp.hpp
+ smart_buffer.hpp
+ udp_simple.hpp
+ udp_zero_copy.hpp
DESTINATION ${HEADER_DIR}/uhd/transport
)
diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp
new file mode 100644
index 000000000..914c02f50
--- /dev/null
+++ b/host/include/uhd/transport/smart_buffer.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <boost/asio.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+#ifndef INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP
+#define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A buffer that knows how to free itself:
+ *
+ * This is just the smart buffer interface.
+ * A transport implementation will have its own
+ * internal (custom) smart buffer implementation.
+ *
+ * A smart buffer contains a boost asio const buffer.
+ * On destruction, the buffer contents will be freed.
+ */
+class smart_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<smart_buffer> sptr;
+ virtual const boost::asio::const_buffer &get(void) const = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP */
diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp_simple.hpp
index 8c6fb096f..8663128ec 100644
--- a/host/include/uhd/transport/udp.hpp
+++ b/host/include/uhd/transport/udp_simple.hpp
@@ -19,32 +19,43 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP
-#define INCLUDED_UHD_TRANSPORT_UDP_HPP
+#ifndef INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP
namespace uhd{ namespace transport{
-class udp : boost::noncopyable{
+class udp_simple : boost::noncopyable{
public:
- typedef boost::shared_ptr<udp> sptr;
+ typedef boost::shared_ptr<udp_simple> sptr;
/*!
- * Make a new udp transport.
+ * Make a new connected udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be control transactions.
+ * The underlying implementation is simple and portable (not fast).
+ *
* The address will be resolved, it can be a host name or ipv4.
* The port will be resolved, it can be a port type or number.
+ *
* \param addr a string representing the destination address
* \param port a string representing the destination port
- * \param bcast if true, enable the broadcast option on the socket
*/
- static sptr make(const std::string &addr, const std::string &port, bool bcast = false);
+ static sptr make_connected(const std::string &addr, const std::string &port);
/*!
- * Send a vector of buffer (like send_msg).
- * Blocks until the data is sent.
- * \param buffs a vector of asio buffers
- * \return the number of bytes sent
+ * Make a new broadcasting udp transport:
+ * This transport can send udp broadcast datagrams
+ * and receive datagrams from multiple sources.
+ * The primary usage for this transport will be to discover devices.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
*/
- virtual size_t send(const std::vector<boost::asio::const_buffer> &buffs) = 0;
+ static sptr make_broadcast(const std::string &addr, const std::string &port);
/*!
* Send a single buffer.
@@ -55,15 +66,7 @@ public:
virtual size_t send(const boost::asio::const_buffer &buff) = 0;
/*!
- * Receive a buffer. Write into the memory provided.
- * Returns empty when data is not available.
- * \param buffs a vector of asio buffers
- * \return the number of bytes received.
- */
- virtual size_t recv(const std::vector<boost::asio::mutable_buffer> &buffs) = 0;
-
- /*!
- * Receive a buffer. Write into the memory provided.
+ * Receive into the provided buffer.
* Returns empty when data is not available.
* \param buff a mutable buffer to receive into
* \return the number of bytes received.
@@ -73,4 +76,4 @@ public:
}} //namespace
-#endif /* INCLUDED_UHD_TRANSPORT_UDP_HPP */
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP */
diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp
new file mode 100644
index 000000000..9c3505dd6
--- /dev/null
+++ b/host/include/uhd/transport/udp_zero_copy.hpp
@@ -0,0 +1,76 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/smart_buffer.hpp>
+#include <boost/asio.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+#ifndef INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A zero copy udp transport provides an efficient way to handle data.
+ * by avoiding the extra copy when recv() is called on the socket.
+ * Rather, the zero copy transport gives the caller a memory reference.
+ * The caller informs the transport when it is finished with the reference.
+ *
+ * On linux systems, the zero copy transport can use a kernel packet ring.
+ * If no platform specific solution is available, make returns a boost asio
+ * implementation that wraps the functionality around a standard recv() call.
+ */
+class udp_zero_copy : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<udp_zero_copy> sptr;
+
+ /*!
+ * Make a new zero copy udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be data transactions.
+ * The underlying implementation is fast and platform specific.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make(const std::string &addr, const std::string &port);
+
+ /*!
+ * Send a single buffer.
+ * Blocks until the data is sent.
+ * \param buff single asio buffer
+ * \return the number of bytes sent
+ */
+ virtual size_t send(const boost::asio::const_buffer &buff) = 0;
+
+ /*!
+ * Receive a buffer.
+ * The memory is managed by the implementation.
+ * Returns an empty buffer when data is not available.
+ * \return a smart buffer with memory and size
+ */
+ virtual smart_buffer::sptr recv(void) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP */
diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp
index da7ec595a..b13786546 100644
--- a/host/include/uhd/usrp/usrp2.hpp
+++ b/host/include/uhd/usrp/usrp2.hpp
@@ -29,6 +29,11 @@ class usrp2 : public device{
public:
/*!
* Discover usrp2 devices over the ethernet.
+ *
+ * Recommended key/value pairs for the device hint address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which may or may not be a broadcast address.
+ *
* This static method will be called by the device::discover.
* \param hint a device addr with the usrp2 address filled in
* \return a vector of device addresses for all usrp2s found
@@ -37,6 +42,11 @@ public:
/*!
* Make a usrp2 from a device address.
+ *
+ * Required key/value pairs for the device address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which must be the specific address of a usrp2.
+ *
* \param addr the device address
* \return a device sptr to a new usrp2
*/
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 97f1ac52e..a52cd74a9 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -23,7 +23,7 @@ SET(libuhd_sources
device_addr.cpp
gain_handler.cpp
wax.cpp
- transport/udp.cpp
+ transport/udp_simple.cpp
usrp/dboard/basic.cpp
usrp/dboard_base.cpp
usrp/dboard_id.cpp
@@ -38,6 +38,13 @@ SET(libuhd_sources
)
########################################################################
+# Conditionally add the udp sources
+########################################################################
+LIST(APPEND libuhd_sources
+ transport/udp_zero_copy_none.cpp
+)
+
+########################################################################
# Conditionally add the usrp1e sources
########################################################################
LIST(APPEND libuhd_sources
diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp
deleted file mode 100644
index 878f71410..000000000
--- a/host/lib/transport/udp.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/transport/udp.hpp>
-#include <boost/format.hpp>
-#include <iostream>
-
-/***********************************************************************
- * UDP implementation class
- **********************************************************************/
-class udp_impl : public uhd::transport::udp{
-public:
- //structors
- udp_impl(const std::string &addr, const std::string &port, bool bcast);
- ~udp_impl(void);
-
- //send/recv
- size_t send(const std::vector<boost::asio::const_buffer> &buffs);
- size_t send(const boost::asio::const_buffer &buff);
- size_t recv(const std::vector<boost::asio::mutable_buffer> &buffs);
- size_t recv(const boost::asio::mutable_buffer &buff);
-
-private:
- boost::asio::ip::udp::socket *_socket;
- boost::asio::ip::udp::endpoint _receiver_endpoint;
- boost::asio::ip::udp::endpoint _sender_endpoint;
- boost::asio::io_service _io_service;
-};
-
-/***********************************************************************
- * UDP public make function
- **********************************************************************/
-uhd::transport::udp::sptr uhd::transport::udp::make(
- const std::string &addr,
- const std::string &port,
- bool bcast
-){
- return uhd::transport::udp::sptr(new udp_impl(addr, port, bcast));
-}
-
-/***********************************************************************
- * UDP implementation methods
- **********************************************************************/
-udp_impl::udp_impl(const std::string &addr, const std::string &port, bool bcast){
- //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
-
- // resolve the address
- boost::asio::ip::udp::resolver resolver(_io_service);
- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
- _receiver_endpoint = *resolver.resolve(query);
-
- // Create and open the socket
- _socket = new boost::asio::ip::udp::socket(_io_service);
- _socket->open(boost::asio::ip::udp::v4());
-
- if (bcast){
- // Allow broadcasting
- boost::asio::socket_base::broadcast option(true);
- _socket->set_option(option);
- }
-
-}
-
-udp_impl::~udp_impl(void){
- delete _socket;
-}
-
-size_t udp_impl::send(const std::vector<boost::asio::const_buffer> &buffs){
- return _socket->send_to(buffs, _receiver_endpoint);
-}
-
-size_t udp_impl::send(const boost::asio::const_buffer &buff){
- return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);
-}
-
-size_t udp_impl::recv(const std::vector<boost::asio::mutable_buffer> &buffs){
- if (_socket->available() == 0) return 0;
- return _socket->receive_from(buffs, _sender_endpoint);
-}
-
-size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){
- if (_socket->available() == 0) return 0;
- return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint);
-}
diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp
new file mode 100644
index 000000000..491cf59db
--- /dev/null
+++ b/host/lib/transport/udp_simple.cpp
@@ -0,0 +1,133 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/udp_simple.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * UDP connected implementation class
+ **********************************************************************/
+class udp_connected_impl : public udp_simple{
+public:
+ //structors
+ udp_connected_impl(const std::string &addr, const std::string &port);
+ ~udp_connected_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+};
+
+udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ // Create, open, and connect the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+}
+
+udp_connected_impl::~udp_connected_impl(void){
+ delete _socket;
+}
+
+size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send(boost::asio::buffer(buff));
+}
+
+size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){
+ if (_socket->available() == 0) return 0;
+ return _socket->receive(boost::asio::buffer(buff));
+}
+
+/***********************************************************************
+ * UDP broadcast implementation class
+ **********************************************************************/
+class udp_broadcast_impl : public udp_simple{
+public:
+ //structors
+ udp_broadcast_impl(const std::string &addr, const std::string &port);
+ ~udp_broadcast_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::ip::udp::endpoint _receiver_endpoint;
+ boost::asio::io_service _io_service;
+};
+
+udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ _receiver_endpoint = *resolver.resolve(query);
+
+ // Create and open the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+
+ // Allow broadcasting
+ boost::asio::socket_base::broadcast option(true);
+ _socket->set_option(option);
+
+}
+
+udp_broadcast_impl::~udp_broadcast_impl(void){
+ delete _socket;
+}
+
+size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);
+}
+
+size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){
+ if (_socket->available() == 0) return 0;
+ boost::asio::ip::udp::endpoint sender_endpoint;
+ return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint);
+}
+
+/***********************************************************************
+ * UDP public make functions
+ **********************************************************************/
+udp_simple::sptr udp_simple::make_connected(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_connected_impl(addr, port));
+}
+
+udp_simple::sptr udp_simple::make_broadcast(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_broadcast_impl(addr, port));
+}
diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp
new file mode 100644
index 000000000..e95706d94
--- /dev/null
+++ b/host/lib/transport/udp_zero_copy_none.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/udp_zero_copy.hpp>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * Smart buffer implementation for udp zerocopy none
+ *
+ * This smart buffer implemention houses a const buffer.
+ * When the smart buffer is deleted, the buffer is freed.
+ * The memory in the const buffer is allocated with new [],
+ * and so the destructor frees the buffer with delete [].
+ **********************************************************************/
+class smart_buffer_impl : public smart_buffer{
+public:
+ smart_buffer_impl(const boost::asio::const_buffer &buff){
+ _buff = buff;
+ }
+
+ ~smart_buffer_impl(void){
+ delete [] boost::asio::buffer_cast<const uint32_t *>(_buff);
+ }
+
+ const boost::asio::const_buffer &get(void) const{
+ return _buff;
+ }
+
+private:
+ boost::asio::const_buffer _buff;
+};
+
+/***********************************************************************
+ * UDP zero copy implementation class
+ *
+ * This is the portable zero copy implementation for systems
+ * where a faster, platform specific solution is not available.
+ *
+ * It uses boost asio udp sockets and the standard recv() class,
+ * and in-fact, is not actually doing a zero-copy implementation.
+ **********************************************************************/
+class udp_zero_copy_impl : public udp_zero_copy{
+public:
+ //structors
+ udp_zero_copy_impl(const std::string &addr, const std::string &port);
+ ~udp_zero_copy_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ smart_buffer::sptr recv(void);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+};
+
+udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ // Create, open, and connect the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+}
+
+udp_zero_copy_impl::~udp_zero_copy_impl(void){
+ delete _socket;
+}
+
+size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send(boost::asio::buffer(buff));
+}
+
+smart_buffer::sptr udp_zero_copy_impl::recv(void){
+ size_t available = _socket->available();
+
+ //allocate memory and create buffer
+ uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)];
+ boost::asio::mutable_buffer buff(buff_mem, available);
+
+ //receive only if data is available
+ if (available > 0){
+ _socket->receive(boost::asio::buffer(buff));
+ }
+
+ //create a new smart buffer to house the data
+ return smart_buffer::sptr(new smart_buffer_impl(buff));
+}
+
+/***********************************************************************
+ * UDP zero copy make function
+ **********************************************************************/
+udp_zero_copy::sptr udp_zero_copy::make(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_zero_copy_impl(addr, port));
+}
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 0ca2409c3..6969e0a89 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -36,12 +36,12 @@ static const float floats_per_short = 1.0/shorts_per_float;
* Helper Functions
**********************************************************************/
void usrp2_impl::io_init(void){
- //initially empty spillover buffer
- _splillover_buff = asio::buffer(_spillover_mem, 0);
+ //initially empty copy buffer
+ _rx_copy_buff = asio::buffer("", 0);
//send a small data packet so the usrp2 knows the udp source port
uint32_t zero_data = 0;
- _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data)));
+ _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data)));
}
#define unrolled_loop(__i, __len, __inst) {\
@@ -57,6 +57,13 @@ void usrp2_impl::io_init(void){
} \
}
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
static inline void host_floats_to_usrp2_items(
uint32_t *usrp2_items,
const fc32_t *host_floats,
@@ -87,9 +94,12 @@ static inline void host_items_to_usrp2_items(
const uint32_t *host_items,
size_t num_samps
){
- unrolled_loop(i, num_samps,
- usrp2_items[i] = htonl(host_items[i])
- );
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i]));
+ }
}
static inline void usrp2_items_to_host_items(
@@ -97,20 +107,22 @@ static inline void usrp2_items_to_host_items(
const uint32_t *usrp2_items,
size_t num_samps
){
- unrolled_loop(i, num_samps,
- host_items[i] = ntohl(usrp2_items[i])
- );
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i]));
+ }
}
/***********************************************************************
* Send Raw Data
**********************************************************************/
-size_t usrp2_impl::send_raw(
- const boost::asio::const_buffer &buff,
- const uhd::metadata_t &metadata
-){
- std::vector<boost::asio::const_buffer> buffs(2);
- uint32_t vrt_hdr[7]; //max size
+size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){
+ size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t);
+ const uint32_t *items = asio::buffer_cast<const uint32_t *>(_tx_copy_buff);
+
+ uint32_t vrt_hdr[_tx_vrt_max_offset_words32];
uint32_t vrt_hdr_flags = 0;
size_t num_vrt_hdr_words = 1;
@@ -131,60 +143,30 @@ size_t usrp2_impl::send_raw(
//fill in complete header word
vrt_hdr[0] = htonl(vrt_hdr_flags |
((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) |
- ((num_vrt_hdr_words + asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff)
+ ((num_vrt_hdr_words + num_items) & 0xffff)
);
- //load the buffer vector
- size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t);
- buffs[0] = asio::buffer(&vrt_hdr, vrt_hdr_size);
- buffs[1] = buff;
+ //copy in the vrt header (yes we left space)
+ std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words);
+ asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t));
//send and return number of samples
- return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t);
+ return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t);
}
/***********************************************************************
* Receive Raw Data
**********************************************************************/
-size_t usrp2_impl::recv_raw(
- const boost::asio::mutable_buffer &buff,
- uhd::metadata_t &metadata
-){
- metadata = metadata_t(); //clear metadata
-
- //handle the case where there is spillover
- if (asio::buffer_size(_splillover_buff) != 0){
- size_t bytes_to_copy = std::min(
- asio::buffer_size(_splillover_buff),
- asio::buffer_size(buff)
- );
- std::memcpy(
- asio::buffer_cast<void*>(buff),
- asio::buffer_cast<const void*>(_splillover_buff),
- bytes_to_copy
- );
- _splillover_buff = asio::buffer(
- asio::buffer_cast<uint8_t*>(_splillover_buff)+bytes_to_copy,
- asio::buffer_size(_splillover_buff)-bytes_to_copy
- );
- //std::cout << boost::format("Copied spillover %d samples") % (bytes_to_copy/sizeof(sc16_t)) << std::endl;
- return bytes_to_copy/sizeof(sc16_t);
- }
-
- //load the buffer vector
- std::vector<boost::asio::mutable_buffer> buffs(3);
- uint32_t vrt_hdr[USRP2_HOST_RX_VRT_HEADER_WORDS32];
- buffs[0] = asio::buffer(vrt_hdr, sizeof(vrt_hdr));
- buffs[1] = buff;
- buffs[2] = asio::buffer(_spillover_mem, _mtu);
+void usrp2_impl::recv_raw(uhd::metadata_t &metadata){
+ //do a receive
+ _rx_smart_buff = _data_transport->recv();
- //receive into the buffers
- size_t bytes_recvd = _data_transport->recv(buffs);
-
- //failure case
- if (bytes_recvd < sizeof(vrt_hdr)) return 0;
+ ////////////////////////////////////////////////////////////////////
+ // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!!
+ ////////////////////////////////////////////////////////////////////
//unpack the vrt header
+ const uint32_t *vrt_hdr = asio::buffer_cast<const uint32_t *>(_rx_smart_buff->get());
metadata = uhd::metadata_t();
uint32_t vrt_header = ntohl(vrt_hdr[0]);
metadata.has_stream_id = true;
@@ -202,13 +184,12 @@ size_t usrp2_impl::recv_raw(
size_t num_words = (vrt_header & 0xffff) -
USRP2_HOST_RX_VRT_HEADER_WORDS32 -
USRP2_HOST_RX_VRT_TRAILER_WORDS32;
- size_t num_bytes = num_words*sizeof(uint32_t);
-
- //handle the case where spillover memory was used
- size_t spillover_size = num_bytes - std::min(num_bytes, asio::buffer_size(buff));
- _splillover_buff = asio::buffer(_spillover_mem, spillover_size);
- return (num_bytes - spillover_size)/sizeof(sc16_t);
+ //setup the rx buffer to point to the data
+ _rx_copy_buff = boost::asio::buffer(
+ vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32,
+ num_words*sizeof(uint32_t)
+ );
}
/***********************************************************************
@@ -219,37 +200,26 @@ size_t usrp2_impl::send(
const uhd::metadata_t &metadata,
const std::string &type
){
- if (type == "32fc"){
- size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t);
- boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t));
+ uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data
+ size_t num_samps = _max_samples_per_packet;
- host_floats_to_usrp2_items(
- asio::buffer_cast<uint32_t*>(raw_buff),
- asio::buffer_cast<const fc32_t*>(buff),
- num_samps
- );
-
- return send_raw(raw_buff, metadata);
+ //calculate the number of samples to be copied
+ //and copy the samples into the send buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
}
-
- if (type == "16sc"){
- #ifdef HAVE_BIG_ENDIAN
- return send_raw(buff, metadata);
- #else
- size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t);
- boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t));
-
- host_items_to_usrp2_items(
- asio::buffer_cast<uint32_t*>(raw_buff),
- asio::buffer_cast<const uint32_t*>(buff),
- num_samps
- );
-
- return send_raw(raw_buff, metadata);
- #endif
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ host_items_to_usrp2_items(items, asio::buffer_cast<const uint32_t*>(buff), num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
}
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
+ //send the samples (this line seems silly, will be better with vrt lib)
+ _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t));
+ return send_raw(metadata); //return num_samps;
}
/***********************************************************************
@@ -260,39 +230,31 @@ size_t usrp2_impl::recv(
uhd::metadata_t &metadata,
const std::string &type
){
- if (type == "32fc"){
- size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t);
- boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
+ //perform a receive if no rx data is waiting to be copied
+ if (asio::buffer_size(_rx_copy_buff) == 0) recv_raw(metadata);
+ //TODO otherwise flag the metadata to show that is is a fragment
- usrp2_items_to_host_floats(
- asio::buffer_cast<fc32_t*>(buff),
- asio::buffer_cast<const uint32_t*>(raw_buff),
- num_samps
- );
+ //extract the number of samples available to copy
+ //and a pointer into the usrp2 received items memory
+ size_t num_samps = asio::buffer_size(_rx_copy_buff)/sizeof(uint32_t);
+ const uint32_t *items = asio::buffer_cast<const uint32_t*>(_rx_copy_buff);
- return num_samps;
+ //calculate the number of samples to be copied
+ //and copy the samples from the recv buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
}
-
- if (type == "16sc"){
- #ifdef HAVE_BIG_ENDIAN
- return recv_raw(buff, metadata);
- #else
- size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t);
- boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
-
- usrp2_items_to_host_items(
- asio::buffer_cast<uint32_t*>(buff),
- asio::buffer_cast<const uint32_t*>(raw_buff),
- num_samps
- );
-
- return num_samps;
- #endif
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ usrp2_items_to_host_items(asio::buffer_cast<uint32_t*>(buff), items, num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
}
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ //update the rx copy buffer to reflect the bytes copied
+ _rx_copy_buff = asio::buffer(items + num_samps, num_samps*sizeof(uint32_t));
+
+ return num_samps;
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 700f94ae1..51082df15 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -23,6 +23,7 @@
using namespace uhd;
using namespace uhd::usrp;
+using namespace uhd::transport;
/***********************************************************************
* Discovery over the udp transport
@@ -33,8 +34,9 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
//create a udp transport to communicate
//TODO if an addr is not provided, search all interfaces?
std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
- transport::udp::sptr udp_transport = \
- transport::udp::make(hint["addr"], ctrl_port, true);
+ udp_simple::sptr udp_transport = udp_simple::make_broadcast(
+ hint["addr"], ctrl_port
+ );
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
@@ -76,16 +78,18 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
/***********************************************************************
* Make
**********************************************************************/
-#define num2str(num) (boost::lexical_cast<std::string>(num))
+template <class T> std::string num2str(T num){
+ return boost::lexical_cast<std::string>(num);
+}
device::sptr usrp2::make(const device_addr_t &device_addr){
//create a control transport
- transport::udp::sptr ctrl_transport = transport::udp::make(
+ udp_simple::sptr ctrl_transport = udp_simple::make_connected(
device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
);
//create a data transport
- transport::udp::sptr data_transport = transport::udp::make(
+ udp_zero_copy::sptr data_transport = udp_zero_copy::make(
device_addr["addr"], num2str(USRP2_UDP_DATA_PORT)
);
@@ -99,8 +103,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){
* Structors
**********************************************************************/
usrp2_impl::usrp2_impl(
- transport::udp::sptr ctrl_transport,
- transport::udp::sptr data_transport
+ udp_simple::sptr ctrl_transport,
+ udp_zero_copy::sptr data_transport
){
_ctrl_transport = ctrl_transport;
_data_transport = data_transport;
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 037aed477..a58bf8471 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -22,7 +22,8 @@
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <uhd/transport/udp.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include "fw_common.h"
@@ -81,8 +82,8 @@ public:
* \param data_transport the udp transport for data
*/
usrp2_impl(
- uhd::transport::udp::sptr ctrl_transport,
- uhd::transport::udp::sptr data_transport
+ uhd::transport::udp_simple::sptr ctrl_transport,
+ uhd::transport::udp_zero_copy::sptr data_transport
);
~usrp2_impl(void);
@@ -103,8 +104,8 @@ public:
private:
//the raw io interface (samples are in the usrp2 native format)
- size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &);
- size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &);
+ size_t send_raw(const uhd::metadata_t &);
+ void recv_raw(uhd::metadata_t &);
uhd::dict<uint32_t, size_t> _tx_stream_id_to_packet_seq;
uhd::dict<uint32_t, size_t> _rx_stream_id_to_packet_seq;
static const size_t _mtu = 1500; //FIXME we have no idea
@@ -114,15 +115,16 @@ private:
USRP2_HOST_RX_VRT_TRAILER_WORDS32 -
((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp)
;
- uint32_t _tmp_send_mem[_mtu/sizeof(uint32_t)];
- uint32_t _tmp_recv_mem[_mtu/sizeof(uint32_t)];
- uint32_t _spillover_mem[_mtu/sizeof(uint32_t)];
- boost::asio::mutable_buffer _splillover_buff;
+ static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib
+ uint32_t _tx_mem[_mtu/sizeof(uint32_t)];
+ boost::asio::const_buffer _tx_copy_buff;
+ uhd::transport::smart_buffer::sptr _rx_smart_buff;
+ boost::asio::const_buffer _rx_copy_buff;
void io_init(void);
//udp transports for control and data
- uhd::transport::udp::sptr _ctrl_transport;
- uhd::transport::udp::sptr _data_transport;
+ uhd::transport::udp_simple::sptr _ctrl_transport;
+ uhd::transport::udp_zero_copy::sptr _data_transport;
//private vars for dealing with send/recv control
uint32_t _ctrl_seq_num;