summaryrefslogtreecommitdiffstats
path: root/host/lib/transport
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-01-19 22:23:46 -0800
committerJosh Blum <josh@joshknows.com>2011-01-19 22:23:46 -0800
commit9239878b0b81c3a368bf11cfc2fe48bfb05ff902 (patch)
treef41a5e58eac89b35cb99537a0a0b64662384a9f2 /host/lib/transport
parentfc138381ee4bd8d191795230b7447071a85e1f28 (diff)
parent7d918c5f6acc9a5d2c8ae03e2e67b403f7efd5ff (diff)
downloaduhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.gz
uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.bz2
uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.zip
Merge branch 'next'
Conflicts: host/lib/usrp/usrp2/codec_impl.cpp
Diffstat (limited to 'host/lib/transport')
-rw-r--r--host/lib/transport/CMakeLists.txt42
-rw-r--r--host/lib/transport/buffer_pool.cpp80
-rw-r--r--host/lib/transport/convert_types_impl.hpp345
-rwxr-xr-xhost/lib/transport/gen_convert_types.py211
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp29
-rw-r--r--host/lib/transport/msvc/stdint.h35
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp26
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp46
8 files changed, 140 insertions, 674 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 0d6226e4c..8765c6703 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2011 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
@@ -23,7 +23,7 @@
# Setup libusb
########################################################################
MESSAGE(STATUS "")
-FIND_PACKAGE(USB1 REQUIRED)
+FIND_PACKAGE(USB1)
LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF)
@@ -37,9 +37,6 @@ IF(ENABLE_USB)
${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.hpp
)
- IF(MSVC) #include our custom stdint for libusb
- INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/msvc)
- ENDIF(MSVC)
ELSE(ENABLE_USB)
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/usb_dummy_impl.cpp
@@ -47,25 +44,6 @@ ELSE(ENABLE_USB)
ENDIF(ENABLE_USB)
########################################################################
-# Check for SIMD headers
-########################################################################
-MESSAGE(STATUS "")
-
-INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H)
-
-IF(HAVE_EMMINTRIN_H)
- ADD_DEFINITIONS(-DHAVE_EMMINTRIN_H)
-ENDIF(HAVE_EMMINTRIN_H)
-
-INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H)
-
-IF(HAVE_ARM_NEON_H)
- ADD_DEFINITIONS(-DHAVE_ARM_NEON_H)
-ENDIF(HAVE_ARM_NEON_H)
-
-########################################################################
# Setup defines for interface address discovery
########################################################################
MESSAGE(STATUS "")
@@ -93,22 +71,8 @@ LIBUHD_PYTHON_GEN_SOURCE(
${CMAKE_CURRENT_BINARY_DIR}/vrt_if_packet.cpp
)
-LIBUHD_PYTHON_GEN_SOURCE(
- ${CMAKE_CURRENT_SOURCE_DIR}/gen_convert_types.py
- ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp
-)
-
-# append this directory to the include path so the generated convert types
-# can include the implementation convert types file in the source directory
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
-
-# make the generated convert types depend on the implementation header
-SET_SOURCE_FILES_PROPERTIES(
- ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp PROPERTIES
- OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/convert_types_impl.hpp
-)
-
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp
${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp
diff --git a/host/lib/transport/buffer_pool.cpp b/host/lib/transport/buffer_pool.cpp
new file mode 100644
index 000000000..971bbb75a
--- /dev/null
+++ b/host/lib/transport/buffer_pool.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright 2011-2011 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/buffer_pool.hpp>
+#include <boost/shared_array.hpp>
+#include <vector>
+
+using namespace uhd::transport;
+
+//! pad the byte count to a multiple of alignment
+static size_t pad_to_boundary(const size_t bytes, const size_t alignment){
+ return bytes + (alignment - bytes)%alignment;
+}
+
+/***********************************************************************
+ * Buffer pool implementation
+ **********************************************************************/
+class buffer_pool_impl : public buffer_pool{
+public:
+ buffer_pool_impl(
+ const std::vector<ptr_type> &ptrs,
+ boost::shared_array<char> mem
+ ): _ptrs(ptrs), _mem(mem){
+ /* NOP */
+ }
+
+ ptr_type at(const size_t index) const{
+ return _ptrs.at(index);
+ }
+
+ size_t size(void) const{
+ return _ptrs.size();
+ }
+
+private:
+ std::vector<ptr_type> _ptrs;
+ boost::shared_array<char> _mem;
+};
+
+/***********************************************************************
+ * Buffer pool factor function
+ **********************************************************************/
+buffer_pool::sptr buffer_pool::make(
+ const size_t num_buffs,
+ const size_t buff_size,
+ const size_t alignment
+){
+ //1) pad the buffer size to be a multiple of alignment
+ //2) pad the overall memory size for room after alignment
+ //3) allocate the memory in one block of sufficient size
+ const size_t padded_buff_size = pad_to_boundary(buff_size, alignment);
+ boost::shared_array<char> mem(new char[padded_buff_size*num_buffs + alignment-1]);
+
+ //Fill a vector with boundary-aligned points in the memory
+ const size_t mem_start = pad_to_boundary(size_t(mem.get()), alignment);
+ std::vector<ptr_type> ptrs(num_buffs);
+ for (size_t i = 0; i < num_buffs; i++){
+ ptrs[i] = ptr_type(mem_start + padded_buff_size*i);
+ }
+
+ //Create a new buffer pool implementation with:
+ // - the pre-computed pointers, and
+ // - the reference to allocated memory.
+ return sptr(new buffer_pool_impl(ptrs, mem));
+}
+
diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp
deleted file mode 100644
index 48ff99725..000000000
--- a/host/lib/transport/convert_types_impl.hpp
+++ /dev/null
@@ -1,345 +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/>.
-//
-
-#ifndef INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP
-#define INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP
-
-#include <uhd/config.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <boost/cstdint.hpp>
-#include <cstring>
-#include <complex>
-
-#ifdef HAVE_EMMINTRIN_H
- #define USE_EMMINTRIN_H //use sse2 intrinsics
-#endif
-
-#if defined(USE_EMMINTRIN_H)
- #include <emmintrin.h>
-#endif
-
-#ifdef HAVE_ARM_NEON_H
- #define USE_ARM_NEON_H
-#endif
-
-#if defined(USE_ARM_NEON_H)
- #include <arm_neon.h>
-#endif
-
-/***********************************************************************
- * Typedefs
- **********************************************************************/
-typedef std::complex<float> fc32_t;
-typedef std::complex<boost::int16_t> sc16_t;
-typedef boost::uint32_t item32_t;
-
-/***********************************************************************
- * Convert complex short buffer to items32
- **********************************************************************/
-static UHD_INLINE item32_t sc16_to_item32(sc16_t num){
- boost::uint16_t real = num.real();
- boost::uint16_t imag = num.imag();
- return (item32_t(real) << 16) | (item32_t(imag) << 0);
-}
-
-static UHD_INLINE void sc16_to_item32_nswap(
- const sc16_t *input, item32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = sc16_to_item32(input[i]);
- }
-}
-
-static UHD_INLINE void sc16_to_item32_bswap(
- const sc16_t *input, item32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = uhd::byteswap(sc16_to_item32(input[i]));
- }
-}
-
-/***********************************************************************
- * Convert items32 buffer to complex short
- **********************************************************************/
-static UHD_INLINE sc16_t item32_to_sc16(item32_t item){
- return sc16_t(
- boost::int16_t(item >> 16),
- boost::int16_t(item >> 0)
- );
-}
-
-static UHD_INLINE void item32_to_sc16_nswap(
- const item32_t *input, sc16_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = item32_to_sc16(input[i]);
- }
-}
-
-static UHD_INLINE void item32_to_sc16_bswap(
- const item32_t *input, sc16_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = item32_to_sc16(uhd::byteswap(input[i]));
- }
-}
-
-/***********************************************************************
- * Convert complex float buffer to items32 (no swap)
- **********************************************************************/
-static const float shorts_per_float = float(32767);
-
-static UHD_INLINE item32_t fc32_to_item32(fc32_t num){
- boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float);
- boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float);
- return (item32_t(real) << 16) | (item32_t(imag) << 0);
-}
-
-////////////////////////////////////
-// none-swap
-////////////////////////////////////
-#if defined(USE_EMMINTRIN_H)
-static UHD_INLINE void fc32_to_item32_nswap(
- const fc32_t *input, item32_t *output, size_t nsamps
-){
- __m128 scalar = _mm_set_ps1(shorts_per_float);
-
- //convert blocks of samples with intrinsics
- size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
- //load from input
- __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0));
- __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2));
-
- //convert and scale
- __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar));
- __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar));
-
- //pack + swap 16-bit pairs
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi);
- tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
- tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
-
- //store to output
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi);
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = fc32_to_item32(input[i]);
- }
-}
-
-#elif defined(USE_ARM_NEON_H)
-static UHD_INLINE void fc32_to_item32_nswap(
- const fc32_t *input, item32_t *output, size_t nsamps)
-{
- size_t i;
-
- float32x4_t Q0 = vdupq_n_f32(shorts_per_float);
- for (i=0; i < (nsamps & ~0x03); i+=2) {
- float32x4_t Q1 = vld1q_f32(reinterpret_cast<const float *>(&input[i]));
- float32x4_t Q2 = vmulq_f32(Q1, Q0);
- int32x4_t Q3 = vcvtq_s32_f32(Q2);
- int16x4_t D8 = vmovn_s32(Q3);
- int16x4_t D9 = vrev32_s16(D8);
- vst1_s16((reinterpret_cast<int16_t *>(&output[i])), D9);
- }
-
- for (; i < nsamps; i++)
- output[i] = fc32_to_item32(input[i]);
-}
-
-#else
-static UHD_INLINE void fc32_to_item32_nswap(
- const fc32_t *input, item32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = fc32_to_item32(input[i]);
- }
-}
-
-#endif
-
-////////////////////////////////////
-// byte-swap
-////////////////////////////////////
-#if defined(USE_EMMINTRIN_H)
-static UHD_INLINE void fc32_to_item32_bswap(
- const fc32_t *input, item32_t *output, size_t nsamps
-){
- __m128 scalar = _mm_set_ps1(shorts_per_float);
-
- //convert blocks of samples with intrinsics
- size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
- //load from input
- __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0));
- __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2));
-
- //convert and scale
- __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar));
- __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar));
-
- //pack + byteswap -> byteswap 16 bit words
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi);
- tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8));
-
- //store to output
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi);
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = uhd::byteswap(fc32_to_item32(input[i]));
- }
-}
-
-#else
-static UHD_INLINE void fc32_to_item32_bswap(
- const fc32_t *input, item32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = uhd::byteswap(fc32_to_item32(input[i]));
- }
-}
-
-#endif
-
-/***********************************************************************
- * Convert items32 buffer to complex float
- **********************************************************************/
-static const float floats_per_short = float(1.0/shorts_per_float);
-
-static UHD_INLINE fc32_t item32_to_fc32(item32_t item){
- return fc32_t(
- float(boost::int16_t(item >> 16)*floats_per_short),
- float(boost::int16_t(item >> 0)*floats_per_short)
- );
-}
-
-////////////////////////////////////
-// none-swap
-////////////////////////////////////
-#if defined(USE_EMMINTRIN_H)
-static UHD_INLINE void item32_to_fc32_nswap(
- const item32_t *input, fc32_t *output, size_t nsamps
-){
- __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16));
- __m128i zeroi = _mm_setzero_si128();
-
- //convert blocks of samples with intrinsics
- size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
- //load from input
- __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i));
-
- //unpack + swap 16-bit pairs
- tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
- tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
- __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits
- __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi);
-
- //convert and scale
- __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar);
- __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar);
-
- //store to output
- _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo);
- _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi);
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_to_fc32(input[i]);
- }
-}
-
-#elif defined(USE_ARM_NEON_H)
-static UHD_INLINE void item32_to_fc32_nswap(
- const item32_t *input, fc32_t *output, size_t nsamps)
-{
- size_t i;
-
- float32x4_t Q1 = vdupq_n_f32(floats_per_short);
- for (i=0; i < (nsamps & ~0x03); i+=2) {
- int16x4_t D0 = vld1_s16(reinterpret_cast<const int16_t *>(&input[i]));
- int16x4_t D1 = vrev32_s16(D0);
- int32x4_t Q2 = vmovl_s16(D1);
- float32x4_t Q3 = vcvtq_f32_s32(Q2);
- float32x4_t Q4 = vmulq_f32(Q3, Q1);
- vst1q_f32((reinterpret_cast<float *>(&output[i])), Q4);
- }
-
- for (; i < nsamps; i++)
- output[i] = item32_to_fc32(input[i]);
-}
-
-#else
-static UHD_INLINE void item32_to_fc32_nswap(
- const item32_t *input, fc32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = item32_to_fc32(input[i]);
- }
-}
-#endif
-
-////////////////////////////////////
-// byte-swap
-////////////////////////////////////
-#if defined(USE_EMMINTRIN_H)
-static UHD_INLINE void item32_to_fc32_bswap(
- const item32_t *input, fc32_t *output, size_t nsamps
-){
- __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16));
- __m128i zeroi = _mm_setzero_si128();
-
- //convert blocks of samples with intrinsics
- size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
- //load from input
- __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i));
-
- //byteswap + unpack -> byteswap 16 bit words
- tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8));
- __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits
- __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi);
-
- //convert and scale
- __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar);
- __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar);
-
- //store to output
- _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo);
- _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi);
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_to_fc32(uhd::byteswap(input[i]));
- }
-}
-
-#else
-static UHD_INLINE void item32_to_fc32_bswap(
- const item32_t *input, fc32_t *output, size_t nsamps
-){
- for (size_t i = 0; i < nsamps; i++){
- output[i] = item32_to_fc32(uhd::byteswap(input[i]));
- }
-}
-
-#endif
-
-#endif /* INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP */
diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py
deleted file mode 100755
index f9509c81d..000000000
--- a/host/lib/transport/gen_convert_types.py
+++ /dev/null
@@ -1,211 +0,0 @@
-#!/usr/bin/env python
-#
-# 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/>.
-#
-
-TMPL_TEXT = """
-#import time
-/***********************************************************************
- * This file was generated by $file on $time.strftime("%c")
- **********************************************************************/
-
-\#include <uhd/config.hpp>
-\#include <uhd/transport/convert_types.hpp>
-\#include <boost/cstdint.hpp>
-\#include <boost/detail/endian.hpp>
-\#include <stdexcept>
-\#include "convert_types_impl.hpp"
-
-using namespace uhd;
-
-/***********************************************************************
- * Generate predicate for jump table
- **********************************************************************/
-UHD_INLINE boost::uint8_t get_pred(
- const io_type_t &io_type,
- const otw_type_t &otw_type,
- size_t num_chans
-){
- boost::uint8_t pred = 0;
-
- switch(otw_type.byteorder){
- \#ifdef BOOST_BIG_ENDIAN
- case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.nswap_p; break;
- case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break;
- \#else
- case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.bswap_p; break;
- case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break;
- \#endif
- case otw_type_t::BO_NATIVE: pred |= $ph.nswap_p; break;
- default: throw std::runtime_error("unhandled otw byteorder type");
- }
-
- switch(otw_type.get_sample_size()){
- case sizeof(boost::uint32_t): pred |= $ph.item32_p; break;
- default: throw std::runtime_error("unhandled otw sample size");
- }
-
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break;
- case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break;
- default: throw std::runtime_error("unhandled io type id");
- }
-
- switch(num_chans){
- case 1: pred |= $ph.chan1_p; break;
- case 2: pred |= $ph.chan2_p; break;
- case 3: pred |= $ph.chan3_p; break;
- case 4: pred |= $ph.chan4_p; break;
- default: throw std::runtime_error("unhandled number of channels");
- }
-
- return pred;
-}
-
-/***********************************************************************
- * Convert host type to device type
- **********************************************************************/
-void transport::convert_io_type_to_otw_type(
- const std::vector<const void *> &io_buffs,
- const io_type_t &io_type,
- void *otw_buff,
- const otw_type_t &otw_type,
- size_t nsamps_per_io_buff
-){
- switch(get_pred(io_type, otw_type, io_buffs.size())){
- #for $pred in range(2**$ph.nbits)
- case $pred:
- #set $out_type = $ph.get_dev_type($pred)
- #set $in_type = $ph.get_host_type($pred)
- #set $num_chans = $ph.get_num_chans($pred)
- #set $converter = '_'.join([$in_type, 'to', $out_type])
- #if $num_chans == 1
- $(converter)_$ph.get_swap_type($pred)(
- reinterpret_cast<const $(in_type)_t *>(io_buffs.front()),
- reinterpret_cast<$(out_type)_t *>(otw_buff),
- nsamps_per_io_buff
- );
- #else
- for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){
- #for $j in range($num_chans)
- reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] =
- #if $ph.get_swap_type($pred) == 'bswap'
- uhd::byteswap($(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]));
- #else
- $(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]);
- #end if
- #end for
- }
- #end if
- break;
- #end for
- }
-}
-
-/***********************************************************************
- * Convert device type to host type
- **********************************************************************/
-void transport::convert_otw_type_to_io_type(
- const void *otw_buff,
- const otw_type_t &otw_type,
- std::vector<void *> &io_buffs,
- const io_type_t &io_type,
- size_t nsamps_per_io_buff
-){
- switch(get_pred(io_type, otw_type, io_buffs.size())){
- #for $pred in range(2**$ph.nbits)
- case $pred:
- #set $out_type = $ph.get_host_type($pred)
- #set $in_type = $ph.get_dev_type($pred)
- #set $num_chans = $ph.get_num_chans($pred)
- #set $converter = '_'.join([$in_type, 'to', $out_type])
- #if $num_chans == 1
- $(converter)_$ph.get_swap_type($pred)(
- reinterpret_cast<const $(in_type)_t *>(otw_buff),
- reinterpret_cast<$(out_type)_t *>(io_buffs.front()),
- nsamps_per_io_buff
- );
- #else
- for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){
- #for $j in range($num_chans)
- reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] =
- #if $ph.get_swap_type($pred) == 'bswap'
- $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]));
- #else
- $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]);
- #end if
- #end for
- }
- #end if
- break;
- #end for
- }
-}
-
-"""
-
-def parse_tmpl(_tmpl_text, **kwargs):
- from Cheetah.Template import Template
- return str(Template(_tmpl_text, kwargs))
-
-class ph:
- bswap_p = 0b00001
- nswap_p = 0b00000
- item32_p = 0b00000
- sc16_p = 0b00010
- fc32_p = 0b00000
- chan1_p = 0b00000
- chan2_p = 0b00100
- chan3_p = 0b01000
- chan4_p = 0b01100
-
- nbits = 4 #see above
-
- @staticmethod
- def has(pred, mask, flag): return (pred & mask) == flag
-
- @staticmethod
- def get_swap_type(pred):
- mask = 0b1
- if ph.has(pred, mask, ph.bswap_p): return 'bswap'
- if ph.has(pred, mask, ph.nswap_p): return 'nswap'
- raise NotImplementedError
-
- @staticmethod
- def get_dev_type(pred):
- mask = 0b0
- if ph.has(pred, mask, ph.item32_p): return 'item32'
- raise NotImplementedError
-
- @staticmethod
- def get_host_type(pred):
- mask = 0b10
- if ph.has(pred, mask, ph.sc16_p): return 'sc16'
- if ph.has(pred, mask, ph.fc32_p): return 'fc32'
- raise NotImplementedError
-
- @staticmethod
- def get_num_chans(pred):
- mask = 0b1100
- if ph.has(pred, mask, ph.chan1_p): return 1
- if ph.has(pred, mask, ph.chan2_p): return 2
- if ph.has(pred, mask, ph.chan3_p): return 3
- if ph.has(pred, mask, ph.chan4_p): return 4
- raise NotImplementedError
-
-if __name__ == '__main__':
- import sys
- open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__, ph=ph))
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index f589d7c77..adc590284 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -18,9 +18,9 @@
#include "libusb1_base.hpp"
#include <uhd/transport/usb_zero_copy.hpp>
#include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/assert.hpp>
-#include <boost/shared_array.hpp>
#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -105,8 +105,8 @@ private:
//! a list of all transfer structs we allocated
std::vector<libusb_transfer *> _all_luts;
- //! a block of memory for the transfer buffers
- boost::shared_array<char> _buffer;
+ //! memory allocated for the transfer buffers
+ buffer_pool::sptr _buffer_pool;
// Calls for processing asynchronous I/O
libusb_transfer *allocate_transfer(void *mem, size_t len);
@@ -134,7 +134,6 @@ static void callback(libusb_transfer *lut){
* \param pointer to libusb_transfer
*/
void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
_completed_list->push_with_wait(lut);
}
@@ -157,9 +156,9 @@ usb_endpoint::usb_endpoint(
_input(input)
{
_completed_list = lut_buff_type::make(num_transfers);
- _buffer = boost::shared_array<char>(new char[num_transfers*transfer_size]);
+ _buffer_pool = buffer_pool::make(num_transfers, transfer_size);
for (size_t i = 0; i < num_transfers; i++){
- _all_luts.push_back(allocate_transfer(_buffer.get() + i*transfer_size, transfer_size));
+ _all_luts.push_back(allocate_transfer(_buffer_pool->at(i), transfer_size));
//input luts are immediately submitted to be filled
//output luts go into the completed list as free buffers
@@ -272,7 +271,6 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut){
}
libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
libusb_transfer *lut;
if (_completed_list->pop_with_timed_wait(lut, timeout)) return lut;
return NULL;
@@ -293,6 +291,7 @@ public:
~libusb_zero_copy_impl(void){
_threads_running = false;
+ _thread_group.interrupt_all();
_thread_group.join_all();
}
@@ -333,12 +332,14 @@ private:
set_thread_priority_safe();
libusb::session::sptr session = libusb::session::get_global_session();
_threads_running = true;
- while(_threads_running){
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000; //100ms
- libusb_handle_events_timeout(session->get_context(), &tv);
- }
+ try{
+ while(_threads_running){
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; //100ms
+ libusb_handle_events_timeout(session->get_context(), &tv);
+ }
+ } catch(const boost::thread_interrupted &){}
}
};
diff --git a/host/lib/transport/msvc/stdint.h b/host/lib/transport/msvc/stdint.h
deleted file mode 100644
index b3eb61aae..000000000
--- a/host/lib/transport/msvc/stdint.h
+++ /dev/null
@@ -1,35 +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/>.
-//
-
-#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H
-#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H
-
-#include <boost/cstdint.hpp>
-
-//provide a stdint implementation for libusb
-
-typedef boost::uint64_t uint64_t;
-typedef boost::uint32_t uint32_t;
-typedef boost::uint16_t uint16_t;
-typedef boost::uint8_t uint8_t;
-
-typedef boost::int64_t int64_t;
-typedef boost::int32_t int32_t;
-typedef boost::int16_t int16_t;
-typedef boost::int8_t int8_t;
-
-#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index c758fa894..5c049cfad 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -18,10 +18,10 @@
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/warning.hpp>
-#include <boost/shared_array.hpp>
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <boost/thread.hpp>
@@ -37,14 +37,15 @@ namespace asio = boost::asio;
**********************************************************************/
//Define this to the the boost async io calls to perform receive.
//Otherwise, get_recv_buff uses a blocking receive with timeout.
-//#define USE_ASIO_ASYNC_RECV
+#define USE_ASIO_ASYNC_RECV
//Define this to the the boost async io calls to perform send.
//Otherwise, the commit callback uses a blocking send.
//#define USE_ASIO_ASYNC_SEND
-//enough buffering for half a second of samples at full rate on usrp2
-static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(4 * 25e6 * 0.5);
+//By default, this buffer is sized insufficiently small.
+//For peformance, this buffer should be 10s of megabytes.
+static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(10e3);
//Large buffers cause more underflow at high rates.
//Perhaps this is due to the kernel scheduling,
@@ -123,16 +124,16 @@ public:
void init(void){
//allocate all recv frames and release them to begin xfers
_pending_recv_buffs = pending_buffs_type::make(_num_recv_frames);
- _recv_buffer = boost::shared_array<char>(new char[_num_recv_frames*_recv_frame_size]);
+ _recv_buffer_pool = buffer_pool::make(_num_recv_frames, _recv_frame_size);
for (size_t i = 0; i < _num_recv_frames; i++){
- release(_recv_buffer.get() + i*_recv_frame_size);
+ release(_recv_buffer_pool->at(i));
}
//allocate all send frames and push them into the fifo
_pending_send_buffs = pending_buffs_type::make(_num_send_frames);
- _send_buffer = boost::shared_array<char>(new char[_num_send_frames*_send_frame_size]);
+ _send_buffer_pool = buffer_pool::make(_num_send_frames, _send_frame_size);
for (size_t i = 0; i < _num_send_frames; i++){
- handle_send(_send_buffer.get() + i*_send_frame_size);
+ handle_send(_send_buffer_pool->at(i));
}
//spawn the service threads that will run the io service
@@ -302,7 +303,7 @@ public:
private:
//memory management -> buffers and fifos
boost::thread_group _thread_group;
- boost::shared_array<char> _send_buffer, _recv_buffer;
+ buffer_pool::sptr _send_buffer_pool, _recv_buffer_pool;
typedef bounded_buffer<asio::mutable_buffer> pending_buffs_type;
pending_buffs_type::sptr _pending_recv_buffs, _pending_send_buffs;
const size_t _recv_frame_size, _num_recv_frames;
@@ -321,12 +322,13 @@ private:
**********************************************************************/
template<typename Opt> static void resize_buff_helper(
udp_zero_copy_asio_impl::sptr udp_trans,
- size_t target_size,
+ const size_t target_size,
const std::string &name
){
size_t min_sock_buff_size = 0;
if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE;
if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE;
+ min_sock_buff_size = std::max(min_sock_buff_size, target_size);
std::string help_message;
#if defined(UHD_PLATFORM_LINUX)
@@ -347,7 +349,7 @@ template<typename Opt> static void resize_buff_helper(
) % name % actual_size << std::endl;
if (actual_size < target_size) uhd::warning::post(str(boost::format(
"The %s buffer is smaller than the requested size.\n"
- "The minimum recommended buffer size is %d bytes.\n"
+ "The minimum requested buffer size is %d bytes.\n"
"See the transport application notes on buffer resizing.\n%s"
) % name % min_sock_buff_size % help_message));
}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
index 278bcfeaa..c535edd04 100644
--- a/host/lib/transport/vrt_packet_handler.hpp
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 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
@@ -26,7 +26,7 @@
#include <uhd/types/otw_type.hpp>
#include <uhd/types/metadata.hpp>
#include <uhd/transport/vrt_if_packet.hpp>
-#include <uhd/transport/convert_types.hpp>
+#include <uhd/convert.hpp>
#include <uhd/transport/zero_copy.hpp>
#include <boost/function.hpp>
#include <stdexcept>
@@ -35,6 +35,9 @@
namespace vrt_packet_handler{
+//this may change in the future but its a constant for now
+static const size_t OTW_BYTES_PER_SAMP = sizeof(boost::uint32_t);
+
template <typename T> UHD_INLINE T get_context_code(
const boost::uint32_t *vrt_hdr,
const uhd::transport::vrt::if_packet_info_t &if_packet_info
@@ -91,6 +94,7 @@ template <typename T> UHD_INLINE T get_context_code(
//vrt unpack each managed buffer
uhd::transport::vrt::if_packet_info_t if_packet_info;
for (size_t i = 0; i < state.width; i++){
+ if (state.managed_buffs[i].get() == NULL) continue; //better have a message packet coming up...
//extract packet words and check thats its enough to move on
size_t num_packet_words32 = state.managed_buffs[i]->size()/sizeof(boost::uint32_t);
@@ -144,8 +148,7 @@ template <typename T> UHD_INLINE T get_context_code(
size_t offset_bytes,
size_t total_samps,
uhd::rx_metadata_t &metadata,
- const uhd::io_type_t &io_type,
- const uhd::otw_type_t &otw_type,
+ uhd::convert::function_type &converter,
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
@@ -183,7 +186,7 @@ template <typename T> UHD_INLINE T get_context_code(
}
//extract the number of samples available to copy
- size_t bytes_per_item = otw_type.get_sample_size();
+ size_t bytes_per_item = OTW_BYTES_PER_SAMP;
size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item;
size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available);
size_t bytes_to_copy = nsamps_to_copy*bytes_per_item;
@@ -198,9 +201,8 @@ template <typename T> UHD_INLINE T get_context_code(
}
//copy-convert the samples from the recv buffer
- uhd::transport::convert_otw_type_to_io_type(
- state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff
- );
+ uhd::convert::input_type otw_buffs(1, state.copy_buffs[i]);
+ converter(otw_buffs, io_buffs, nsamps_to_copy_per_io_buff);
//update the rx copy buffer to reflect the bytes copied
state.copy_buffs[i] += bytes_to_copy;
@@ -234,6 +236,11 @@ template <typename T> UHD_INLINE T get_context_code(
size_t vrt_header_offset_words32 = 0,
size_t chans_per_otw_buff = 1
){
+ uhd::convert::function_type converter(
+ uhd::convert::get_converter_otw_to_cpu(
+ io_type, otw_type, 1, chans_per_otw_buff
+ ));
+
switch(recv_mode){
////////////////////////////////////////////////////////////////
@@ -244,7 +251,7 @@ template <typename T> UHD_INLINE T get_context_code(
buffs, 0,
total_num_samps,
metadata,
- io_type, otw_type,
+ converter,
tick_rate,
vrt_unpacker,
get_recv_buffs,
@@ -265,7 +272,7 @@ template <typename T> UHD_INLINE T get_context_code(
buffs, accum_num_samps*io_type.size,
total_num_samps - accum_num_samps,
(accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept
- io_type, otw_type,
+ converter,
tick_rate,
vrt_unpacker,
get_recv_buffs,
@@ -309,15 +316,14 @@ template <typename T> UHD_INLINE T get_context_code(
const size_t offset_bytes,
const size_t num_samps,
uhd::transport::vrt::if_packet_info_t &if_packet_info,
- const uhd::io_type_t &io_type,
- const uhd::otw_type_t &otw_type,
+ uhd::convert::function_type &converter,
const vrt_packer_t &vrt_packer,
const get_send_buffs_t &get_send_buffs,
const size_t vrt_header_offset_words32,
const size_t chans_per_otw_buff
){
//load the rest of the if_packet_info in here
- if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t);
+ if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*OTW_BYTES_PER_SAMP)/sizeof(boost::uint32_t);
if_packet_info.packet_count = state.next_packet_seq;
//get send buffers for each channel
@@ -337,9 +343,8 @@ template <typename T> UHD_INLINE T get_context_code(
otw_mem += if_packet_info.num_header_words32;
//copy-convert the samples into the send buffer
- uhd::transport::convert_io_type_to_otw_type(
- io_buffs, io_type, otw_mem, otw_type, num_samps
- );
+ uhd::convert::output_type otw_buffs(1, otw_mem);
+ converter(io_buffs, otw_buffs, num_samps);
//commit the samples to the zero-copy interface
size_t num_bytes_total = (vrt_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t);
@@ -367,6 +372,11 @@ template <typename T> UHD_INLINE T get_context_code(
size_t vrt_header_offset_words32 = 0,
size_t chans_per_otw_buff = 1
){
+ uhd::convert::function_type converter(
+ uhd::convert::get_converter_cpu_to_otw(
+ io_type, otw_type, chans_per_otw_buff, 1
+ ));
+
//translate the metadata to vrt if packet info
uhd::transport::vrt::if_packet_info_t if_packet_info;
if_packet_info.has_sid = false;
@@ -402,7 +412,7 @@ template <typename T> UHD_INLINE T get_context_code(
buffs_, 0,
std::min(total_num_samps_, max_samples_per_packet),
if_packet_info,
- io_type, otw_type,
+ converter,
vrt_packer,
get_send_buffs,
vrt_header_offset_words32,
@@ -435,7 +445,7 @@ template <typename T> UHD_INLINE T get_context_code(
buffs, total_num_samps_sent*io_type.size,
std::min(total_num_samps_unsent, max_samples_per_packet),
if_packet_info,
- io_type, otw_type,
+ converter,
vrt_packer,
get_send_buffs,
vrt_header_offset_words32,