aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/CMakeLists.txt1
-rw-r--r--host/examples/CMakeLists.txt4
-rw-r--r--host/examples/rx_timed_samples.cpp13
-rw-r--r--host/examples/tx_timed_samples.cpp92
-rw-r--r--host/include/uhd/config.hpp9
-rw-r--r--host/include/uhd/device.hpp57
-rw-r--r--host/include/uhd/transport/zero_copy.hpp12
-rw-r--r--host/include/uhd/types/mac_addr.hpp2
-rw-r--r--host/include/uhd/types/otw_type.hpp6
-rw-r--r--host/include/uhd/usrp/device_props.hpp4
-rw-r--r--host/lib/transport/CMakeLists.txt1
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp136
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp358
-rw-r--r--host/lib/types.cpp119
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp8
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp162
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp50
19 files changed, 749 insertions, 295 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index f2725e4b3..0b2d3f012 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -62,6 +62,7 @@ IF(UNIX)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI)
#only export symbols that are declared to be part of the uhd api:
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations
ENDIF(UNIX)
IF(WIN32)
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 242857625..a537c0901 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -18,3 +18,7 @@
ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)
TARGET_LINK_LIBRARIES(rx_timed_samples uhd)
INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+
+ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
+TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
+INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 4b8774036..d2306c7c4 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
int seconds_in_future;
size_t total_num_samps;
- double rx_rate;
+ double rx_rate, freq;
//setup the program options
po::options_description desc("Allowed options");
@@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
- po::notify(vm);
+ po::notify(vm);
//print the help message
if (vm.count("help")){
@@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
sdev->set_rx_rate(rx_rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_rx_freq(freq);
sdev->set_time_now(uhd::time_spec_t(0));
//setup streaming
@@ -78,10 +80,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
size_t num_acc_samps = 0; //number of accumulated samples
while(num_acc_samps < total_num_samps){
uhd::rx_metadata_t md;
- std::complex<float> buff[1000];
+ std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
size_t num_rx_samps = dev->recv(
- boost::asio::buffer(buff, sizeof(buff)),
- md, uhd::io_type_t::COMPLEX_FLOAT32
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
);
if (num_rx_samps == 0) continue; //wait for packets with contents
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
new file mode 100644
index 000000000..6dee69cd5
--- /dev/null
+++ b/host/examples/tx_timed_samples.cpp
@@ -0,0 +1,92 @@
+//
+// 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/utils/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //variables to be set by po
+ std::string args;
+ int seconds_in_future;
+ size_t total_num_samps;
+ double tx_rate, freq;
+ float ampl;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
+ ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ("ampl", po::value<float>(&ampl)->default_value(0.3), "amplitude of each sample")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl;
+
+ //set properties on the device
+ std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
+ sdev->set_tx_rate(tx_rate);
+ std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_tx_freq(freq);
+ sdev->set_time_now(uhd::time_spec_t(0));
+
+ //data to send
+ std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl));
+ uhd::tx_metadata_t md;
+ md.start_of_burst = true;
+ md.end_of_burst = true;
+ md.has_time_spec = true;
+ md.time_spec = uhd::time_spec_t(seconds_in_future);
+
+ //send the entire buffer, let the driver handle fragmentation
+ size_t num_tx_samps = dev->send(
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::SEND_MODE_FULL_BUFF
+ );
+ std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl;
+
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 32eafc89b..fea95145c 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -76,4 +76,13 @@
#define UHD_LOCAL
#endif // UHD_DLL
+// Define force inline macro
+#ifdef BOOST_MSVC
+ #define UHD_INLINE __forceinline
+#elif defined(__GNUG__) && __GNUG__ >= 4
+ #define UHD_INLINE inline __attribute__((always_inline))
+#else
+ #define UHD_INLINE inline
+#endif
+
#endif /* INCLUDED_UHD_CONFIG_HPP */
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index ae75e6dc8..27b461184 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -77,15 +77,35 @@ public:
static sptr make(const device_addr_t &hint, size_t which = 0);
/*!
+ * Send modes for the device send routine.
+ */
+ enum send_mode_t{
+ //! Tells the send routine to send the entire buffer
+ SEND_MODE_FULL_BUFF = 0,
+ //! Tells the send routine to return after one packet
+ SEND_MODE_ONE_PACKET = 1
+ };
+
+ /*!
+ * Recv modes for the device recv routine.
+ */
+ enum recv_mode_t{
+ //! Tells the recv routine to recv the entire buffer
+ RECV_MODE_FULL_BUFF = 0,
+ //! Tells the recv routine to return after one packet
+ RECV_MODE_ONE_PACKET = 1
+ };
+
+ /*!
* Send a buffer containing IF data with its metadata.
*
* Send handles fragmentation as follows:
- * If the buffer has more samples than the maximum supported,
- * the send method will send the maximum number of samples
- * as supported by the transport and return the number sent.
- * In this case, the end of burst flag will be forced to false.
- * It is up to the caller to call send again on the un-sent
- * portions of the buffer, until the buffer is exhausted.
+ * If the buffer has more samples than the maximum per packet,
+ * the send method will fragment the samples across several packets.
+ * Send will respect the burst flags when fragmenting to ensure
+ * that start of burst can only be set on the first fragment and
+ * that end of burst can only be set on the final fragment.
+ * Fragmentation only applies in the full buffer send mode.
*
* This is a blocking call and will not return until the number
* of samples returned have been read out of the buffer.
@@ -93,12 +113,14 @@ public:
* \param buff a buffer pointing to some read-only memory
* \param metadata data describing the buffer's contents
* \param io_type the type of data loaded in the buffer
+ * \param send_mode tells send how to unload the buffer
* \return the number of samples sent
*/
virtual size_t send(
const boost::asio::const_buffer &buff,
const tx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ send_mode_t send_mode = SEND_MODE_ONE_PACKET
) = 0;
/*!
@@ -123,16 +145,35 @@ public:
* immediately when no packets are available to the transport layer,
* and that the timeout duration is reasonably tuned for performance.
*
+ * When using the full buffer recv mode, the metadata only applies
+ * to the first packet received and written into the recv buffer.
+ * Use the one packet recv mode to get per packet metadata.
+ *
* \param buff the buffer to fill with IF data
* \param metadata data to fill describing the buffer
* \param io_type the type of data to fill into the buffer
+ * \param recv_mode tells recv how to load the buffer
* \return the number of samples received
*/
virtual size_t recv(
const boost::asio::mutable_buffer &buff,
rx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ recv_mode_t recv_mode = RECV_MODE_ONE_PACKET
) = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on send.
+ * \return the number of samples
+ */
+ virtual size_t get_max_send_samps_per_packet(void) const = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on recv.
+ * \return the number of samples
+ */
+ virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+
};
} //namespace uhd
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index 4fc1df9de..fdc5b141c 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -45,7 +45,7 @@ public:
* Get the size of the underlying buffer.
* \return the number of bytes
*/
- size_t size(void){
+ size_t size(void) const{
return boost::asio::buffer_size(this->get());
}
@@ -53,7 +53,7 @@ public:
* Get a pointer to the underlying buffer.
* \return a pointer into memory
*/
- template <class T> T cast(void){
+ template <class T> T cast(void) const{
return boost::asio::buffer_cast<T>(this->get());
}
@@ -63,7 +63,7 @@ private:
* The buffer has a reference to memory and a size.
* \return a boost asio const buffer
*/
- virtual const boost::asio::const_buffer &get(void) = 0;
+ virtual const boost::asio::const_buffer &get(void) const = 0;
};
/*!
@@ -87,7 +87,7 @@ public:
* Get the size of the underlying buffer.
* \return the number of bytes
*/
- size_t size(void){
+ size_t size(void) const{
return boost::asio::buffer_size(this->get());
}
@@ -95,7 +95,7 @@ public:
* Get a pointer to the underlying buffer.
* \return a pointer into memory
*/
- template <class T> T cast(void){
+ template <class T> T cast(void) const{
return boost::asio::buffer_cast<T>(this->get());
}
@@ -105,7 +105,7 @@ private:
* The buffer has a reference to memory and a size.
* \return a boost asio mutable buffer
*/
- virtual const boost::asio::mutable_buffer &get(void) = 0;
+ virtual const boost::asio::mutable_buffer &get(void) const = 0;
};
/*!
diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp
index 034b6a348..0ced2e734 100644
--- a/host/include/uhd/types/mac_addr.hpp
+++ b/host/include/uhd/types/mac_addr.hpp
@@ -58,7 +58,7 @@ namespace uhd{
private:
mac_addr_t(const byte_vector_t &bytes); //private constructor
- byte_vector_t _bytes; //internal representation
+ const byte_vector_t _bytes; //internal representation
};
} //namespace uhd
diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp
index f10664584..8e3e65d78 100644
--- a/host/include/uhd/types/otw_type.hpp
+++ b/host/include/uhd/types/otw_type.hpp
@@ -55,6 +55,12 @@ namespace uhd{
BO_NOT_APPLICABLE = '|'
} byteorder;
+ /*!
+ * Get the sample size of this otw type.
+ * \return the size of a sample in bytes
+ */
+ size_t get_sample_size(void) const;
+
otw_type_t(void);
};
diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp
index b8f6f5cd4..983bcb672 100644
--- a/host/include/uhd/usrp/device_props.hpp
+++ b/host/include/uhd/usrp/device_props.hpp
@@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{
enum device_prop_t{
DEVICE_PROP_NAME = 'n', //ro, std::string
DEVICE_PROP_MBOARD = 'm', //ro, wax::obj
- DEVICE_PROP_MBOARD_NAMES = 'M', //ro, prop_names_t
- DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t
- DEVICE_PROP_MAX_TX_SAMPLES = 't' //ro, size_t
+ DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t
};
////////////////////////////////////////////////////////////////////////
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index a36f0fc03..ed8c35225 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -49,4 +49,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp
${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp
${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp
)
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index ee44803f4..56ba391d3 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -16,9 +16,9 @@
//
#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/asio.hpp>
-#include <boost/thread.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -26,65 +26,56 @@ using namespace uhd::transport;
/***********************************************************************
* Managed receive buffer implementation for udp zero-copy asio:
- * Frees the memory held by the const buffer on done.
**********************************************************************/
class managed_recv_buffer_impl : public managed_recv_buffer{
public:
managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){
- _done = false;
+ /* NOP */
}
~managed_recv_buffer_impl(void){
- if (not _done) this->done();
+ /* NOP */
}
void done(void){
- _done = true;
- delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff);
+ /* NOP */
}
private:
- const boost::asio::const_buffer &get(void){
+ const boost::asio::const_buffer &get(void) const{
return _buff;
}
const boost::asio::const_buffer _buff;
- bool _done;
};
/***********************************************************************
* Managed send buffer implementation for udp zero-copy asio:
- * Sends and frees the memory held by the mutable buffer on done.
**********************************************************************/
class managed_send_buffer_impl : public managed_send_buffer{
public:
managed_send_buffer_impl(
const boost::asio::mutable_buffer &buff,
boost::asio::ip::udp::socket *socket
- ) : _buff(buff){
- _done = false;
- _socket = socket;
+ ) : _buff(buff), _socket(socket){
+ /* NOP */
}
~managed_send_buffer_impl(void){
- if (not _done) this->done(0);
+ /* NOP */
}
void done(size_t num_bytes){
- _done = true;
- boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff);
- _socket->send(boost::asio::buffer(mem, num_bytes));
- delete [] mem;
+ _socket->send(boost::asio::buffer(_buff, num_bytes));
}
private:
- const boost::asio::mutable_buffer &get(void){
+ const boost::asio::mutable_buffer &get(void) const{
return _buff;
}
const boost::asio::mutable_buffer _buff;
boost::asio::ip::udp::socket *_socket;
- bool _done;
};
/***********************************************************************
@@ -94,8 +85,12 @@ private:
* However, it is not a true zero copy implementation as each
* send and recv requires a copy operation to/from userspace.
**********************************************************************/
+static const size_t max_buff_size = 2000; //assume max size on send and recv
+
class udp_zero_copy_impl : public udp_zero_copy{
public:
+ typedef boost::shared_ptr<udp_zero_copy_impl> sptr;
+
//structors
udp_zero_copy_impl(const std::string &addr, const std::string &port);
~udp_zero_copy_impl(void);
@@ -104,23 +99,27 @@ public:
managed_recv_buffer::sptr get_recv_buff(void);
managed_send_buffer::sptr get_send_buff(void);
- //resize
- size_t resize_recv_buff(size_t num_bytes){
- boost::asio::socket_base::receive_buffer_size option(num_bytes);
- _socket->set_option(option);
+ //manage buffer
+ template <typename Opt> size_t get_buff_size(void){
+ Opt option;
_socket->get_option(option);
return option.value();
}
- size_t resize_send_buff(size_t num_bytes){
- boost::asio::socket_base::send_buffer_size option(num_bytes);
+
+ template <typename Opt> size_t resize_buff(size_t num_bytes){
+ Opt option(num_bytes);
_socket->set_option(option);
- _socket->get_option(option);
- return option.value();
+ return get_buff_size<Opt>();
}
private:
boost::asio::ip::udp::socket *_socket;
boost::asio::io_service _io_service;
+
+ //send and recv buffer memory (allocated once)
+ boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size];
+
+ managed_send_buffer::sptr _send_buff;
};
udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
@@ -131,10 +130,25 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin
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
+ // 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);
+
+ // create the managed send buff (just once)
+ _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl(
+ boost::asio::buffer(_send_mem, max_buff_size), _socket
+ ));
+
+ // set recv timeout
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; //100 ms
+ UHD_ASSERT_THROW(setsockopt(
+ _socket->native(),
+ SOL_SOCKET, SO_RCVTIMEO,
+ (const char *)&tv, sizeof(timeval)
+ ) == 0);
}
udp_zero_copy_impl::~udp_zero_copy_impl(void){
@@ -142,61 +156,55 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){
}
managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
- //implement timeout through polling and sleeping
- size_t available = 0;
- boost::asio::deadline_timer timer(_socket->get_io_service());
- timer.expires_from_now(boost::posix_time::milliseconds(100));
- while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }
-
- //receive only if data is available
- boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];
- if (available){
- available = _socket->receive(boost::asio::buffer(buff_mem, available));
- }
+ //call recv() with timeout option
+ size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size));
//create a new managed buffer to house the data
return managed_recv_buffer::sptr(
- new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available))
+ new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes))
);
}
managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){
- boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)];
- return managed_send_buffer::sptr(
- new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket)
- );
+ return _send_buff;
}
/***********************************************************************
* UDP zero copy make function
**********************************************************************/
+template<typename Opt> static inline void resize_buff_helper(
+ udp_zero_copy_impl::sptr udp_trans,
+ size_t target_size,
+ const std::string &name
+){
+ static const size_t min_buff_size = size_t(100e3);
+
+ //resize the buffer if size was provided
+ if (target_size > 0){
+ size_t actual_size = udp_trans->resize_buff<Opt>(target_size);
+ if (target_size != actual_size) std::cout << boost::format(
+ "Target %s buffer size: %d\n"
+ "Actual %s byffer size: %d"
+ ) % name % target_size % name % actual_size << std::endl;
+ }
+
+ //otherwise, ensure that the buffer is at least the minimum size
+ else if (udp_trans->get_buff_size<Opt>() < min_buff_size){
+ resize_buff_helper<Opt>(udp_trans, min_buff_size, name);
+ }
+}
+
udp_zero_copy::sptr udp_zero_copy::make(
const std::string &addr,
const std::string &port,
size_t recv_buff_size,
size_t send_buff_size
){
- boost::shared_ptr<udp_zero_copy_impl> udp_trans(new udp_zero_copy_impl(addr, port));
-
- //resize the recv buffer if size was provided
- if (recv_buff_size > 0){
- size_t actual_bytes = udp_trans->resize_recv_buff(recv_buff_size);
- if (recv_buff_size != actual_bytes) std::cout << boost::format(
- "Target recv buffer size: %d\n"
- "Actual recv byffer size: %d"
- ) % recv_buff_size % actual_bytes << std::endl;
- }
+ udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port));
- //resize the send buffer if size was provided
- if (send_buff_size > 0){
- size_t actual_bytes = udp_trans->resize_send_buff(send_buff_size);
- if (send_buff_size != actual_bytes) std::cout << boost::format(
- "Target send buffer size: %d\n"
- "Actual send byffer size: %d"
- ) % send_buff_size % actual_bytes << std::endl;
- }
+ //call the helper to resize send and recv buffers
+ resize_buff_helper<boost::asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv");
+ resize_buff_helper<boost::asio::socket_base::send_buffer_size> (udp_trans, send_buff_size, "send");
return udp_trans;
}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
new file mode 100644
index 000000000..c857db1c4
--- /dev/null
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -0,0 +1,358 @@
+//
+// 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_VRT_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/convert_types.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/function.hpp>
+#include <iostream>
+
+namespace vrt_packet_handler{
+
+/***********************************************************************
+ * vrt packet handler for recv
+ **********************************************************************/
+ struct recv_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ //state variables to handle fragments
+ uhd::transport::managed_recv_buffer::sptr managed_buff;
+ boost::asio::const_buffer copy_buff;
+ size_t fragment_offset_in_samps;
+
+ recv_state(void){
+ //first expected seq is zero
+ next_packet_seq = 0;
+
+ //initially empty copy buffer
+ copy_buff = boost::asio::buffer("", 0);
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t;
+
+ static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Unpack a received vrt header and set the copy buffer.
+ * - helper function for vrt_packet_handler::_recv1
+ ******************************************************************/
+ static UHD_INLINE void _recv1_helper(
+ recv_state &state,
+ uhd::rx_metadata_t &metadata,
+ double tick_rate,
+ size_t vrt_header_offset_words32
+ ){
+ size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t);
+ if (num_packet_words32 <= vrt_header_offset_words32){
+ state.copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
+ const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
+ size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
+ uhd::transport::vrt::unpack(
+ metadata, //output
+ vrt_hdr, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out, //output
+ tick_rate
+ );
+
+ //handle the packet count / sequence number
+ if (packet_count_out != state.next_packet_seq){
+ std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16;
+ }
+ state.next_packet_seq = (packet_count_out+1)%16;
+
+ //setup the buffer to point to the data
+ state.copy_buff = boost::asio::buffer(
+ vrt_hdr + num_header_words32_out,
+ num_payload_words32_out*sizeof(boost::uint32_t)
+ );
+ }
+
+ /*******************************************************************
+ * Recv data, unpack a vrt header, and copy-convert the data.
+ * - helper function for vrt_packet_handler::recv
+ ******************************************************************/
+ static UHD_INLINE size_t _recv1(
+ recv_state &state,
+ void *recv_mem,
+ size_t total_samps,
+ uhd::rx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32,
+ const recv_cb_t& recv_cb
+ ){
+ //perform a receive if no rx data is waiting to be copied
+ if (boost::asio::buffer_size(state.copy_buff) == 0){
+ state.fragment_offset_in_samps = 0;
+ state.managed_buff = zc_iface->get_recv_buff();
+ recv_cb(state.managed_buff); //callback before vrt unpack
+ _recv1_helper(
+ state, metadata, tick_rate, vrt_header_offset_words32
+ );
+ }
+
+ //extract the number of samples available to copy
+ size_t bytes_per_item = otw_type.get_sample_size();
+ size_t bytes_available = boost::asio::buffer_size(state.copy_buff);
+ size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item);
+
+ //setup the fragment flags and offset
+ metadata.more_fragments = total_samps < num_samps;
+ metadata.fragment_offset = state.fragment_offset_in_samps;
+ state.fragment_offset_in_samps += num_samps; //set for next call
+
+ //copy-convert the samples from the recv buffer
+ uhd::transport::convert_otw_type_to_io_type(
+ boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type,
+ recv_mem, io_type, num_samps
+ );
+
+ //update the rx copy buffer to reflect the bytes copied
+ size_t bytes_copied = num_samps*bytes_per_item;
+ state.copy_buff = boost::asio::buffer(
+ boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied,
+ bytes_available - bytes_copied
+ );
+
+ return num_samps;
+ }
+
+ /*******************************************************************
+ * Recv vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t recv(
+ recv_state &state,
+ const boost::asio::mutable_buffer &buff,
+ uhd::rx_metadata_t &metadata,
+ uhd::device::recv_mode_t recv_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const recv_cb_t& recv_cb = &recv_cb_nop
+ ){
+ metadata = uhd::rx_metadata_t(); //init the metadata
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+
+ switch(recv_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ return _recv1(
+ state,
+ boost::asio::buffer_cast<void *>(buff),
+ total_num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ size_t num_samps = 0;
+ uhd::rx_metadata_t tmp_md;
+ while(num_samps < total_num_samps){
+ num_samps += _recv1(
+ state,
+ boost::asio::buffer_cast<boost::uint8_t *>(buff) + (num_samps*io_type.size),
+ total_num_samps - num_samps,
+ (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ }
+ return total_num_samps;
+ }
+ }//switch(recv_mode)
+ }
+
+/***********************************************************************
+ * vrt packet handler for send
+ **********************************************************************/
+ struct send_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ send_state(void){
+ next_packet_seq = 0;
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t;
+
+ static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Pack a vrt header, copy-convert the data, and send it.
+ * - helper function for vrt_packet_handler::send
+ ******************************************************************/
+ static UHD_INLINE void _send1(
+ send_state &state,
+ const void *send_mem,
+ size_t num_samps,
+ const uhd::tx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t vrt_header_offset_words32,
+ const send_cb_t& send_cb
+ ){
+ //get a new managed send buffer
+ uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff();
+ boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32;
+
+ size_t num_header_words32, num_packet_words32;
+ size_t packet_count = state.next_packet_seq++;
+
+ //pack metadata into a vrt header
+ uhd::transport::vrt::pack(
+ metadata, //input
+ tx_mem, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count, //input
+ tick_rate
+ );
+
+ //copy-convert the samples into the send buffer
+ uhd::transport::convert_io_type_to_otw_type(
+ send_mem, io_type,
+ tx_mem + num_header_words32, otw_type,
+ num_samps
+ );
+
+ send_cb(send_buff); //callback after memory filled
+
+ //commit the samples to the zero-copy interface
+ send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
+ }
+
+ /*******************************************************************
+ * Send vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t send(
+ send_state &state,
+ const boost::asio::const_buffer &buff,
+ const uhd::tx_metadata_t &metadata,
+ uhd::device::send_mode_t send_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t max_samples_per_packet,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const send_cb_t& send_cb = &send_cb_nop
+ ){
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+ switch(send_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ size_t num_samps = std::min(total_num_samps, max_samples_per_packet);
+ _send1(
+ state,
+ boost::asio::buffer_cast<const void *>(buff),
+ num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ return num_samps;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ //calculate constants for fragmentation
+ const size_t final_packet_samps = total_num_samps%max_samples_per_packet;
+ const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet;
+ static const size_t first_fragment_index = 0;
+ const size_t final_fragment_index = num_fragments-1;
+
+ //make a rw copy of the metadata to re-flag below
+ uhd::tx_metadata_t md(metadata);
+
+ //loop through the following fragment indexes
+ for (size_t n = first_fragment_index; n <= final_fragment_index; n++){
+
+ //calculate new flags for the fragments
+ md.has_time_spec = md.has_time_spec and (n == first_fragment_index);
+ md.start_of_burst = md.start_of_burst and (n == first_fragment_index);
+ md.end_of_burst = md.end_of_burst and (n == final_fragment_index);
+
+ //send the fragment with the helper function
+ _send1(
+ state,
+ boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size),
+ (n == final_fragment_index)?final_packet_samps:max_samples_per_packet,
+ md,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ }
+ return total_num_samps;
+ }
+ }//switch(send_mode)
+ }
+
+} //namespace vrt_packet_handler
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index 33eb550a1..daf3be7f7 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -42,73 +42,89 @@ using namespace uhd;
/***********************************************************************
* ranges
**********************************************************************/
-gain_range_t::gain_range_t(float min_, float max_, float step_){
- min = min_;
- max = max_;
- step = step_;
+gain_range_t::gain_range_t(float min, float max, float step):
+ min(min),
+ max(max),
+ step(step)
+{
+ /* NOP */
}
-freq_range_t::freq_range_t(double min_, double max_){
- min = min_;
- max = max_;
+freq_range_t::freq_range_t(double min, double max):
+ min(min),
+ max(max)
+{
+ /* NOP */
}
/***********************************************************************
* tune result
**********************************************************************/
-tune_result_t::tune_result_t(void){
- target_inter_freq = 0.0;
- actual_inter_freq = 0.0;
- target_dsp_freq = 0.0;
- actual_dsp_freq = 0.0;
- spectrum_inverted = false;
+tune_result_t::tune_result_t(void):
+ target_inter_freq(0.0),
+ actual_inter_freq(0.0),
+ target_dsp_freq(0.0),
+ actual_dsp_freq(0.0),
+ spectrum_inverted(false)
+{
+ /* NOP */
}
/***********************************************************************
* clock config
**********************************************************************/
-clock_config_t::clock_config_t(void){
- ref_source = REF_INT,
- pps_source = PPS_INT,
- pps_polarity = PPS_NEG;
+clock_config_t::clock_config_t(void):
+ ref_source(REF_INT),
+ pps_source(PPS_INT),
+ pps_polarity(PPS_NEG)
+{
+ /* NOP */
}
/***********************************************************************
* stream command
**********************************************************************/
-stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode_){
- stream_mode = stream_mode_;
- stream_now = true;
- num_samps = 0;
+stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
+ stream_mode(stream_mode),
+ num_samps(0),
+ stream_now(true)
+{
+ /* NOP */
}
/***********************************************************************
* metadata
**********************************************************************/
-rx_metadata_t::rx_metadata_t(void){
- stream_id = 0;
- has_stream_id = false;
- time_spec = time_spec_t();
- has_time_spec = false;
- more_fragments = false;
- fragment_offset = 0;
+rx_metadata_t::rx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ more_fragments(false),
+ fragment_offset(0)
+{
+ /* NOP */
}
-tx_metadata_t::tx_metadata_t(void){
- stream_id = 0;
- has_stream_id = false;
- time_spec = time_spec_t();
- has_time_spec = false;
- start_of_burst = false;
- end_of_burst = false;
+tx_metadata_t::tx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ start_of_burst(false),
+ end_of_burst(false)
+{
+ /* NOP */
}
/***********************************************************************
* time spec
**********************************************************************/
-time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){
- secs = secs_;
- nsecs = nsecs_;
+time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs):
+ secs(secs),
+ nsecs(nsecs)
+{
+ /* NOP */
}
boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
@@ -165,9 +181,8 @@ std::string device_addr_t::to_string(void) const{
/***********************************************************************
* mac addr
**********************************************************************/
-mac_addr_t::mac_addr_t(const byte_vector_t &bytes){
- UHD_ASSERT_THROW(bytes.size() == 6);
- _bytes = bytes;
+mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){
+ UHD_ASSERT_THROW(_bytes.size() == 6);
}
mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){
@@ -220,10 +235,16 @@ std::string mac_addr_t::to_string(void) const{
/***********************************************************************
* otw type
**********************************************************************/
-otw_type_t::otw_type_t(void){
- width = 0;
- shift = 0;
- byteorder = BO_NATIVE;
+size_t otw_type_t::get_sample_size(void) const{
+ return (this->width * 2) / 8;
+}
+
+otw_type_t::otw_type_t(void):
+ width(0),
+ shift(0),
+ byteorder(BO_NATIVE)
+{
+ /* NOP */
}
/***********************************************************************
@@ -251,9 +272,11 @@ io_type_t::io_type_t(size_t size)
/***********************************************************************
* serial
**********************************************************************/
-spi_config_t::spi_config_t(edge_t edge){
- mosi_edge = edge;
- miso_edge = edge;
+spi_config_t::spi_config_t(edge_t edge):
+ mosi_edge(edge),
+ miso_edge(edge)
+{
+ /* NOP */
}
void i2c_iface::write_eeprom(
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index db8d8a886..4c5207203 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -79,7 +79,9 @@ public:
_ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
_ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
+ _ad9510_regs.bypass_divider_out7 = 1;
this->write_reg(0x43);
+ this->write_reg(0x57);
this->update_regs();
}
@@ -88,7 +90,9 @@ public:
_ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
_ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ _ad9510_regs.bypass_divider_out6 = 1;
this->write_reg(0x42);
+ this->write_reg(0x55);
this->update_regs();
}
@@ -130,7 +134,9 @@ private:
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
_ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
+ _ad9510_regs.bypass_divider_out3 = 1;
this->write_reg(0x3F);
+ this->write_reg(0x4F);
this->update_regs();
}
@@ -139,7 +145,9 @@ private:
_ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
_ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ _ad9510_regs.bypass_divider_out4 = 1;
this->write_reg(0x40);
+ this->write_reg(0x51);
this->update_regs();
}
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 7c9d003ce..b6ab919e7 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -31,16 +31,15 @@ namespace asio = boost::asio;
* 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;
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
- //initially empty copy buffer
- _rx_copy_buff = asio::buffer("", 0);
-
- //init the expected rx seq number
- _rx_stream_id_to_packet_seq[0] = 0;
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
//send a small data packet so the usrp2 knows the udp source port
managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
@@ -49,7 +48,8 @@ void usrp2_impl::io_init(void){
send_buff->done(sizeof(data));
//setup RX DSP regs
- _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet);
+ std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl;
+ _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
_iface->poke32(FR_RX_CTRL_NCHANNELS, 1);
_iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset
_iface->poke32(FR_RX_CTRL_VRT_HEADER, 0
@@ -63,98 +63,22 @@ void usrp2_impl::io_init(void){
}
/***********************************************************************
- * Receive Raw Data
- **********************************************************************/
-void usrp2_impl::recv_raw(rx_metadata_t &metadata){
- //do a receive
- _rx_smart_buff = _data_transport->get_recv_buff();
-
- //unpack the vrt header
- size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t);
- if (num_packet_words32 == 0){
- _rx_copy_buff = boost::asio::buffer("", 0);
- return; //must exit here after setting the buffer
- }
- const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>();
- size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
- try{
- vrt::unpack(
- metadata, //output
- vrt_hdr, //input
- num_header_words32_out, //output
- num_payload_words32_out, //output
- num_packet_words32, //input
- packet_count_out, //output
- get_master_clock_freq()
- );
- }catch(const std::exception &e){
- std::cerr << "bad vrt header: " << e.what() << std::endl;
- _rx_copy_buff = boost::asio::buffer("", 0);
- return; //must exit here after setting the buffer
- }
-
- //handle the packet count / sequence number
- size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id];
- if (packet_count_out != expected_packet_count){
- std::cerr << "S" << (packet_count_out - expected_packet_count)%16;
- }
- _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16;
-
- //setup the rx buffer to point to the data
- _rx_copy_buff = asio::buffer(
- vrt_hdr + num_header_words32_out,
- num_payload_words32_out*sizeof(boost::uint32_t)
- );
-}
-
-/***********************************************************************
* Send Data
**********************************************************************/
size_t usrp2_impl::send(
const asio::const_buffer &buff,
- const tx_metadata_t &metadata_,
- const io_type_t &io_type
+ const tx_metadata_t &metadata,
+ const io_type_t &io_type,
+ send_mode_t send_mode
){
- tx_metadata_t metadata = metadata_; //rw copy to change later
-
- transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
- boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();
- size_t num_samps = std::min(std::min(
- asio::buffer_size(buff)/io_type.size,
- size_t(_max_tx_samples_per_packet)),
- send_buff->size()/io_type.size
+ return vrt_packet_handler::send(
+ _packet_handler_send_state, //last state of the send handler
+ buff, metadata, send_mode, //buffer to empty and samples metadata
+ io_type, _tx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport, //zero copy interface
+ get_max_send_samps_per_packet()
);
-
- //kill the end of burst flag if this is a fragment
- if (asio::buffer_size(buff)/io_type.size < num_samps)
- metadata.end_of_burst = false;
-
- size_t num_header_words32, num_packet_words32;
- size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++;
-
- //pack metadata into a vrt header
- vrt::pack(
- metadata, //input
- tx_mem, //output
- num_header_words32, //output
- num_samps, //input
- num_packet_words32, //output
- packet_count, //input
- get_master_clock_freq()
- );
-
- boost::uint32_t *items = tx_mem + num_header_words32; //offset for data
-
- //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));
- return num_samps;
}
/***********************************************************************
@@ -163,44 +87,14 @@ size_t usrp2_impl::send(
size_t usrp2_impl::recv(
const asio::mutable_buffer &buff,
rx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ recv_mode_t recv_mode
){
- //perform a receive if no rx data is waiting to be copied
- if (asio::buffer_size(_rx_copy_buff) == 0){
- _fragment_offset_in_samps = 0;
- recv_raw(metadata);
- }
- //otherwise flag the metadata to show that is is a fragment
- else{
- metadata = rx_metadata_t();
- }
-
- //extract the number of samples available to copy
- //and a pointer into the usrp2 received items memory
- size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff);
- if (bytes_to_copy == 0) return 0; //nothing to receive
- size_t num_samps = std::min(
- asio::buffer_size(buff)/io_type.size,
- bytes_to_copy/sizeof(boost::uint32_t)
+ return vrt_packet_handler::recv(
+ _packet_handler_recv_state, //last state of the recv handler
+ buff, metadata, recv_mode, //buffer to fill and samples metadata
+ io_type, _rx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport //zero copy interface
);
- const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff);
-
- //setup the fragment flags and offset
- metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps;
- metadata.fragment_offset = _fragment_offset_in_samps;
- _fragment_offset_in_samps += num_samps; //set for next time
-
- //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(
- items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t)
- );
-
- return num_samps;
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 9ae68d158..f17efd88e 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
//issue the stream command
_iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD(
- (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1),
+ (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1),
(stream_cmd.stream_now)? 1 : 0,
(inst_chain)? 1 : 0,
(inst_reload)? 1 : 0
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 2b7bdeea2..af3ec216a 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, "");
return;
- case DEVICE_PROP_MAX_RX_SAMPLES:
- val = size_t(_max_rx_samples_per_packet);
- return;
-
- case DEVICE_PROP_MAX_TX_SAMPLES:
- val = size_t(_max_tx_samples_per_packet);
- return;
-
default: UHD_THROW_PROP_GET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index c5b6af810..afea9683c 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -33,6 +33,7 @@
#include <uhd/transport/vrt.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
+#include "../../transport/vrt_packet_handler.hpp"
/*!
* Make a usrp2 dboard interface.
@@ -103,8 +104,24 @@ public:
~usrp2_impl(void);
//the io interface
- size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);
- size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);
+ size_t get_max_send_samps_per_packet(void) const{
+ return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size();
+ }
+ size_t send(
+ const boost::asio::const_buffer &,
+ const uhd::tx_metadata_t &,
+ const uhd::io_type_t &,
+ uhd::device::send_mode_t
+ );
+ size_t get_max_recv_samps_per_packet(void) const{
+ return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size();
+ }
+ size_t recv(
+ const boost::asio::mutable_buffer &,
+ uhd::rx_metadata_t &,
+ const uhd::io_type_t &,
+ uhd::device::recv_mode_t
+ );
private:
double get_master_clock_freq(void){
@@ -121,25 +138,24 @@ private:
codec_ctrl::sptr _codec_ctrl;
serdes_ctrl::sptr _serdes_ctrl;
- //the raw io interface (samples are in the usrp2 native format)
- void recv_raw(uhd::rx_metadata_t &);
- uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq;
- uhd::dict<boost::uint32_t, size_t> _rx_stream_id_to_packet_seq;
+ /*******************************************************************
+ * Deal with the rx and tx packet sizes
+ ******************************************************************/
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)
- static const size_t _max_rx_samples_per_packet =
- (_mtu - _hdrs)/sizeof(boost::uint32_t) -
- USRP2_HOST_RX_VRT_HEADER_WORDS32 -
- USRP2_HOST_RX_VRT_TRAILER_WORDS32
+ static const size_t _max_rx_bytes_per_packet =
+ _mtu - _hdrs -
+ USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) -
+ USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)
;
- static const size_t _max_tx_samples_per_packet =
- (_mtu - _hdrs)/sizeof(boost::uint32_t) -
- uhd::transport::vrt::max_header_words32
+ static const size_t _max_tx_bytes_per_packet =
+ _mtu - _hdrs -
+ uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)
;
- 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;
+
+ vrt_packet_handler::recv_state _packet_handler_recv_state;
+ vrt_packet_handler::send_state _packet_handler_send_state;
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
void io_init(void);
//udp transports for control and data