aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-04-12 13:39:09 -0700
committerJosh Blum <josh@joshknows.com>2010-04-12 13:39:09 -0700
commite611e610f64b473cdd9d0aa5e40690d7550c3cc0 (patch)
tree235c21fd842e05264fd54f85d7ce4045fae42901 /host
parent0021abf18aaf3831d8aaa40574f1876c4f346a92 (diff)
downloaduhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.tar.gz
uhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.tar.bz2
uhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.zip
Added data type conversion routines to transport api.
Diffstat (limited to 'host')
-rw-r--r--host/include/uhd/transport/CMakeLists.txt1
-rw-r--r--host/include/uhd/transport/convert_types.hpp59
-rw-r--r--host/include/uhd/transport/vrt.hpp2
-rw-r--r--host/lib/CMakeLists.txt1
-rw-r--r--host/lib/transport/convert_types.cpp144
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp11
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp128
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp2
8 files changed, 236 insertions, 112 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index 9a94ead1b..4cefffa24 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -17,6 +17,7 @@
INSTALL(FILES
+ convert_types.hpp
if_addrs.hpp
udp_simple.hpp
udp_zero_copy.hpp
diff --git a/host/include/uhd/transport/convert_types.hpp b/host/include/uhd/transport/convert_types.hpp
new file mode 100644
index 000000000..a4d999240
--- /dev/null
+++ b/host/include/uhd/transport/convert_types.hpp
@@ -0,0 +1,59 @@
+//
+// 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/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP
+#define INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * Convert IO samples to OWT samples.
+ *
+ * \param io_buff memory containing samples
+ * \param io_type the type of these samples
+ * \param otw_buff memory to write converted samples
+ * \param otw_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+);
+
+/*!
+ * Convert OTW samples to IO samples.
+ *
+ * \param otw_buff memory containing samples
+ * \param otw_type the type of these samples
+ * \param io_buff memory to write converted samples
+ * \param io_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+);
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP */
diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp
index 04945b347..c30a73489 100644
--- a/host/include/uhd/transport/vrt.hpp
+++ b/host/include/uhd/transport/vrt.hpp
@@ -26,7 +26,7 @@ namespace uhd{ namespace transport{
namespace vrt{
- static const size_t max_header_words32 = 7;
+ static const size_t max_header_words32 = 5; //hdr+sid+tsi+tsf (no class id supported)
/*!
* Pack a vrt header from metadata.
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index a5345cae4..fac1bd19f 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -24,6 +24,7 @@ SET(libuhd_sources
load_modules.cpp
types.cpp
wax.cpp
+ transport/convert_types.cpp
transport/if_addrs.cpp
transport/udp_simple.cpp
transport/vrt.cpp
diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp
new file mode 100644
index 000000000..2a6854f50
--- /dev/null
+++ b/host/lib/transport/convert_types.cpp
@@ -0,0 +1,144 @@
+//
+// 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/convert_types.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/asio.hpp> //endianness conversion
+#include <boost/cstdint.hpp>
+
+using namespace uhd;
+
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+typedef std::complex<float> fc32_t;
+
+static const float shorts_per_float = float(1 << 15);
+static const float floats_per_short = float(1.0/shorts_per_float);
+
+#define unrolled_loop(__inst, __len){ \
+ size_t __i = 0; \
+ for(; __i < (__len & ~0x3); __i+= 4){ \
+ __inst(__i+0); __inst(__i+1); \
+ __inst(__i+2); __inst(__i+3); \
+ } \
+ for(; __i < __len; __i++){ \
+ __inst(__i); \
+ } \
+}
+
+// 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(
+ boost::uint32_t *usrp2_items,
+ const fc32_t *host_floats,
+ size_t num_samps
+){
+ #define host_floats_to_usrp2_items_i(i){ \
+ boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
+ boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
+ usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
+ }
+ unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
+}
+
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_floats_i(i){ \
+ boost::uint32_t item = ntohl(usrp2_items[i]); \
+ boost::int16_t real = boost::uint16_t(item >> 16); \
+ boost::int16_t imag = boost::uint16_t(item >> 0); \
+ host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
+ }
+ unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
+}
+
+static inline void host_items_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const boost::uint32_t *host_items,
+ size_t num_samps
+){
+ #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(host_items_to_usrp2_items_i, num_samps);
+ }
+}
+
+static inline void usrp2_items_to_host_items(
+ boost::uint32_t *host_items,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(usrp2_items_to_host_items_i, num_samps);
+ }
+}
+
+void transport::convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps);
+ break;
+ case io_type_t::COMPLEX_INT16:
+ host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps);
+ break;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
+
+void transport::convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ break;
+ case io_type_t::COMPLEX_INT16:
+ usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ break;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index 13fd50f65..3e0e80bd8 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -110,6 +110,9 @@ private:
size_t get_recv_buff_size(void);
void set_recv_buff_size(size_t);
+
+ static const size_t _mtu = 1500; //FIXME we have no idea
+ static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)
};
udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
@@ -143,7 +146,7 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){
}
managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
- boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)];
+ boost::uint32_t *buff_mem = new boost::uint32_t[_mtu/sizeof(boost::uint32_t)];
//implement timeout through polling and sleeping
size_t available = 0;
@@ -155,7 +158,7 @@ managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
//receive only if data is available
if (available){
- available = _socket->receive(boost::asio::buffer(buff_mem, available));
+ available = _socket->receive(boost::asio::buffer(buff_mem, _mtu));
}
//create a new managed buffer to house the data
@@ -165,9 +168,9 @@ managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
}
managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){
- boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)];
+ boost::uint32_t *buff_mem = new boost::uint32_t[_mtu/sizeof(boost::uint32_t)];
return managed_send_buffer::sptr(
- new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 1500), _socket)
+ new managed_send_buffer_impl(boost::asio::buffer(buff_mem, _mtu-_hdrs), _socket)
);
}
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index a54c0a409..19a1ecf0f 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -15,9 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <complex>
-#include <boost/format.hpp>
#include "usrp2_impl.hpp"
+#include <uhd/transport/convert_types.hpp>
+#include <boost/format.hpp>
+#include <complex>
using namespace uhd;
using namespace uhd::usrp;
@@ -25,18 +26,14 @@ using namespace uhd::transport;
namespace asio = boost::asio;
/***********************************************************************
- * Constants
- **********************************************************************/
-typedef std::complex<float> fc32_t;
-typedef std::complex<boost::int16_t> sc16_t;
-
-static const float shorts_per_float = float(1 << 15);
-static const float floats_per_short = float(1.0/shorts_per_float);
-
-/***********************************************************************
* Helper Functions
**********************************************************************/
void usrp2_impl::io_init(void){
+ //setup otw type
+ _otw_type.width = 16;
+ _otw_type.shift = 0;
+ _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+
//initially empty copy buffer
_rx_copy_buff = asio::buffer("", 0);
@@ -51,79 +48,6 @@ void usrp2_impl::io_init(void){
send_buff->done(sizeof(data));
}
-#define unrolled_loop(__inst, __len){ \
- size_t __i = 0; \
- for(; __i < (__len & ~0x3); __i+= 4){ \
- __inst(__i+0); __inst(__i+1); \
- __inst(__i+2); __inst(__i+3); \
- } \
- for(; __i < __len; __i++){ \
- __inst(__i); \
- } \
-}
-
-// 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(
- boost::uint32_t *usrp2_items,
- const fc32_t *host_floats,
- size_t num_samps
-){
- #define host_floats_to_usrp2_items_i(i){ \
- boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
- boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
- usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
- }
- unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
-}
-
-static inline void usrp2_items_to_host_floats(
- fc32_t *host_floats,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_floats_i(i){ \
- boost::uint32_t item = ntohl(usrp2_items[i]); \
- boost::int16_t real = boost::uint16_t(item >> 16); \
- boost::int16_t imag = boost::uint16_t(item >> 0); \
- host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
- }
- unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
-}
-
-static inline void host_items_to_usrp2_items(
- boost::uint32_t *usrp2_items,
- const boost::uint32_t *host_items,
- size_t num_samps
-){
- #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
- if (is_big_endian){
- std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(host_items_to_usrp2_items_i, num_samps);
- }
-}
-
-static inline void usrp2_items_to_host_items(
- boost::uint32_t *host_items,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
- if (is_big_endian){
- std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(usrp2_items_to_host_items_i, num_samps);
- }
-}
-
/***********************************************************************
* Receive Raw Data
**********************************************************************/
@@ -182,7 +106,7 @@ size_t usrp2_impl::send(
boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();
size_t num_samps = std::min(
asio::buffer_size(buff),
- send_buff->size()
+ send_buff->size()-vrt::max_header_words32*sizeof(boost::uint32_t)
)/io_type.size;
//kill the end of burst flag if this is a fragment
@@ -204,17 +128,12 @@ size_t usrp2_impl::send(
boost::uint32_t *items = tx_mem + num_header_words32; //offset for data
- //copy the samples into the send buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples into the send buffer
+ convert_io_type_to_otw_type(
+ asio::buffer_cast<const void*>(buff), io_type,
+ (void*)items, _otw_type,
+ num_samps
+ );
//send and return number of samples
send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
@@ -254,17 +173,12 @@ size_t usrp2_impl::recv(
metadata.fragment_offset = _fragment_offset_in_samps;
_fragment_offset_in_samps += num_samps; //set for next time
- //copy the samples from the recv buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples from the recv buffer
+ convert_otw_type_to_io_type(
+ (const void*)items, _otw_type,
+ asio::buffer_cast<void*>(buff), io_type,
+ num_samps
+ );
//update the rx copy buffer to reflect the bytes copied
_rx_copy_buff = asio::buffer(
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index be09c4ee1..4e7154afa 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -20,6 +20,7 @@
#include <uhd/usrp/usrp2.hpp>
#include <uhd/types/dict.hpp>
+#include <uhd/types/otw_type.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
#include <boost/asio.hpp>
@@ -139,6 +140,7 @@ private:
uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;
boost::asio::const_buffer _rx_copy_buff;
size_t _fragment_offset_in_samps;
+ uhd::otw_type_t _otw_type;
void io_init(void);
//udp transports for control and data