From d42e588d76efc41d18dabc75027347fe123904d1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 22 Feb 2010 11:42:32 -0800 Subject: Moved the udp implementation guts into the cpp file --- host/lib/transport/udp.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp index 06defb107..af60760a5 100644 --- a/host/lib/transport/udp.cpp +++ b/host/lib/transport/udp.cpp @@ -20,7 +20,42 @@ #include #include -uhd::transport::udp::udp(const std::string &addr, const std::string &port, bool bcast){ +/*********************************************************************** + * UDP implementation class + **********************************************************************/ +class udp_impl : public uhd::transport::udp{ +public: + //structors + udp_impl(const std::string &addr, const std::string &port, bool bcast); + ~udp_impl(void); + + //send/recv + void send(const std::vector &buffs); + void send(const boost::asio::const_buffer &buff); + uhd::shared_iovec recv(void); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::ip::udp::endpoint _receiver_endpoint; + boost::asio::ip::udp::endpoint _sender_endpoint; + boost::asio::io_service _io_service; +}; + +/*********************************************************************** + * UDP public make function + **********************************************************************/ +uhd::transport::udp::sptr uhd::transport::udp::make( + const std::string &addr, + const std::string &port, + bool bcast +){ + return uhd::transport::udp::sptr(new udp_impl(addr, port, bcast)); +} + +/*********************************************************************** + * UDP implementation methods + **********************************************************************/ +udp_impl::udp_impl(const std::string &addr, const std::string &port, bool bcast){ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; // resolve the address @@ -40,20 +75,20 @@ uhd::transport::udp::udp(const std::string &addr, const std::string &port, bool } -uhd::transport::udp::~udp(void){ +udp_impl::~udp_impl(void){ delete _socket; } -void uhd::transport::udp::send(const std::vector &buffs){ +void udp_impl::send(const std::vector &buffs){ _socket->send_to(buffs, _receiver_endpoint); } -void uhd::transport::udp::send(const boost::asio::const_buffer &buff){ +void udp_impl::send(const boost::asio::const_buffer &buff){ std::vector buffs = boost::assign::list_of(buff); send(buffs); } -uhd::shared_iovec uhd::transport::udp::recv(void){ +uhd::shared_iovec udp_impl::recv(void){ //allocate a buffer for the number of bytes available (could be zero) uhd::shared_iovec iov(_socket->available()); //call recv only if data is available -- cgit v1.2.3 From 6b7c53985c09a8d74e9bfd9c6b37948d458b2c44 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 22 Feb 2010 18:47:05 -0800 Subject: Work on the io interface for a device (and some implementation work in usrp2). Modified the udp transport to reflect some of these changes. Got the fw compiling again, and it will not set data to true for small payloads (configuration ones). --- firmware/microblaze/apps/Makefile.am | 2 +- firmware/microblaze/apps/txrx.c | 5 ++- host/CMakeLists.txt | 9 +++++ host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/device.hpp | 33 +++++++++++++--- host/include/uhd/metadata.hpp | 47 +++++++++++++++++++++++ host/include/uhd/transport/udp.hpp | 17 ++++++++- host/lib/transport/udp.cpp | 20 ++++++---- host/lib/usrp/usrp2/usrp2_impl.cpp | 74 ++++++++++++++++++++++++++++++++++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 4 +- 10 files changed, 189 insertions(+), 23 deletions(-) create mode 100644 host/include/uhd/metadata.hpp (limited to 'host/lib/transport') diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/Makefile.am index 6d993ef8c..ff426cf8c 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common LDADD = $(top_srcdir)/lib/libu2fw.a -AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp/mboard +AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp noinst_PROGRAMS = txrx.elf diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 77c8e498c..16aa8eab2 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -159,7 +159,10 @@ void handle_udp_data_packet( unsigned char *payload, int payload_len ){ //TODO store the reply port - _is_data = true; + + //forward this data to the dsp when the payload is sufficient + //the small payload is used to give the device the udp source port + _is_data = payload_len > sizeof(uint32_t); } #define OTW_GPIO_BANK_TO_NUM(bank) \ diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 70c04631b..30f4789a3 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -72,6 +72,15 @@ FIND_PACKAGE(Boost 1.36 REQUIRED INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) +######################################################################## +# Setup Endianess +######################################################################## +INCLUDE(TestBigEndian) +TEST_BIG_ENDIAN(HAVE_BIG_ENDIAN) +IF(HAVE_BIG_ENDIAN) + ADD_DEFINITIONS("-DHAVE_BIG_ENDIAN=/* */") +ENDIF(HAVE_BIG_ENDIAN) + ######################################################################## # Create Uninstall Target ######################################################################## diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 006c54f22..e87f74291 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -24,6 +24,7 @@ INSTALL(FILES device_addr.hpp dict.hpp gain_handler.hpp + metadata.hpp props.hpp shared_iovec.hpp time_spec.hpp diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index dfbfbd7c0..da58d4f85 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -20,13 +20,12 @@ #include #include +#include #include #include #include #include #include -#include -#include namespace uhd{ @@ -72,9 +71,33 @@ public: */ device_addr_t get_device_addr(void); - //the io interface - virtual void send_raw(const std::vector &) = 0; - virtual uhd::shared_iovec recv_raw(void) = 0; + /*! + * Send a buffer containing IF data with its metadata. + * + * \param buff a buffer pointing to some read-only memory + * \param metadata data describing the buffer's contents + * \param the type of data loaded in the buffer (32fc, 16sc) + * \return the number of bytes sent + */ + virtual size_t send( + const boost::asio::const_buffer &buff, + const metadata_t &metadata, + const std::string &type = "32fc" + ) = 0; + + /*! + * Receive a buffer containing IF data and its metadata. + * + * \param buff the buffer to fill with IF data + * \param metadata data to fill describing the buffer + * \param the type of data to fill into the buffer (32fc, 16sc) + * \return the number of bytes received + */ + virtual size_t recv( + const boost::asio::mutable_buffer &buff, + metadata_t &metadata, + const std::string &type = "32fc" + ) = 0; }; } //namespace uhd diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp new file mode 100644 index 000000000..43b91d1b0 --- /dev/null +++ b/host/include/uhd/metadata.hpp @@ -0,0 +1,47 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_METADATA_HPP +#define INCLUDED_UHD_METADATA_HPP + +#include + +namespace uhd{ + +/*! + * Metadata structure for describing the IF data. + * Includes stream ID, time specification, and burst flags. + * The receive routines will convert IF data headers into metadata. + * The send routines will convert the metadata to IF data headers. + */ +struct metadata_t{ + uint32_t stream_id; + time_spec_t time_spec; + bool start_of_burst; + bool end_of_burst; + + metadata_t(void){ + stream_id = 0; + time_spec = time_spec_t(); + start_of_burst = false; + end_of_burst = false; + } +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_METADATA_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp index 554234b43..07d84e62a 100644 --- a/host/include/uhd/transport/udp.hpp +++ b/host/include/uhd/transport/udp.hpp @@ -41,18 +41,31 @@ public: /*! * Send a vector of buffer (like send_msg). + * Blocks until the data is sent. * \param buffs a vector of asio buffers + * \return the number of bytes sent */ - virtual void send(const std::vector &buffs) = 0; + virtual size_t send(const std::vector &buffs) = 0; /*! * Send a single buffer. + * Blocks until the data is sent. * \param buff single asio buffer + * \return the number of bytes sent */ - virtual void send(const boost::asio::const_buffer &buff) = 0; + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + /*! + * Receive a buffer. Write into the memory provided. + * Returns empty when data is not available. + * \param buff a mutable buffer to receive into + * \return the number of bytes received. + */ + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; /*! * Receive a buffer. The memory is managed internally. + * Returns zero when data is not available. * Calling recv will invalidate the buffer of the previous recv. * \return a shared iovec with allocated memory */ diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp index af60760a5..fca4dd7d6 100644 --- a/host/lib/transport/udp.cpp +++ b/host/lib/transport/udp.cpp @@ -17,7 +17,6 @@ #include #include -#include #include /*********************************************************************** @@ -30,8 +29,9 @@ public: ~udp_impl(void); //send/recv - void send(const std::vector &buffs); - void send(const boost::asio::const_buffer &buff); + size_t send(const std::vector &buffs); + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); uhd::shared_iovec recv(void); private: @@ -79,13 +79,17 @@ udp_impl::~udp_impl(void){ delete _socket; } -void udp_impl::send(const std::vector &buffs){ - _socket->send_to(buffs, _receiver_endpoint); +size_t udp_impl::send(const std::vector &buffs){ + return _socket->send_to(buffs, _receiver_endpoint); } -void udp_impl::send(const boost::asio::const_buffer &buff){ - std::vector buffs = boost::assign::list_of(buff); - send(buffs); +size_t udp_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); +} + +size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); } uhd::shared_iovec udp_impl::recv(void){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index f44964394..47bf06aff 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -130,6 +130,10 @@ usrp2_impl::usrp2_impl( //init the tx and rx dboards (do last) dboard_init(); + //send a small data packet so the usrp2 knows the udp source port + uint32_t zero_data = 0; + _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data))); + } usrp2_impl::~usrp2_impl(void){ @@ -204,10 +208,72 @@ void usrp2_impl::set(const wax::obj &, const wax::obj &){ /*********************************************************************** * IO Interface **********************************************************************/ -void usrp2_impl::send_raw(const std::vector &){ - return; +static const float float_scale_factor = pow(2.0, 15); + +size_t usrp2_impl::send( + const boost::asio::const_buffer &buff, + const uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + //extract the buffer elements + const float *float_buff = boost::asio::buffer_cast(buff); + const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); + + //convert floats into the shorts buffer + int16_t *shorts_buff = new int16_t[buff_len]; + for (size_t i = 0; i < buff_len; i++){ + shorts_buff[i] = float_buff[i]*float_scale_factor; + } + + //send from a buffer of shorts + size_t bytes_sent = send( + boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), + metadata, "sc16" + ); + + //cleanup + delete [] shorts_buff; + return bytes_sent; + } + + if (type == "sc16"){ + throw std::runtime_error("not implemented"); + } + + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } -uhd::shared_iovec usrp2_impl::recv_raw(void){ - throw std::runtime_error("not implemented"); +size_t usrp2_impl::recv( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + //extract the buffer elements + float *float_buff = boost::asio::buffer_cast(buff); + const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); + + //receive into a buffer of shorts + int16_t *shorts_buff = new int16_t[buff_len]; + size_t bytes_received = recv( + boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), + metadata, "sc16" + ); + + //convert floats into the shorts buffer + for (size_t i = 0; i < bytes_received/sizeof(int16_t); i++){ + float_buff[i] = shorts_buff[i]/float_scale_factor; + } + + //cleanup + delete [] shorts_buff; + return bytes_received; + } + + if (type == "sc16"){ + throw std::runtime_error("not implemented"); + } + + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2545efd58..2476bcf1d 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -98,8 +98,8 @@ public: double get_master_clock_freq(void); //the io interface - void send_raw(const std::vector &); - uhd::shared_iovec recv_raw(void); + size_t send(const boost::asio::const_buffer &, const uhd::metadata_t &, const std::string &); + size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &); private: //udp transports for control and data -- cgit v1.2.3 From 8050fda48d69f46788672a9ceaccd8d82500ac05 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 23 Feb 2010 16:27:49 -0800 Subject: Added IF data io handing within the usrp2 impl. It packs and unpacks vrt headers/metadata. NOT YET TESTED IN ANY WAY... --- host/include/uhd/CMakeLists.txt | 1 - host/include/uhd/device.hpp | 4 +- host/include/uhd/metadata.hpp | 4 + host/include/uhd/shared_iovec.hpp | 54 -------- host/include/uhd/transport/udp.hpp | 15 +-- host/lib/CMakeLists.txt | 2 +- host/lib/shared_iovec.cpp | 28 ---- host/lib/transport/udp.cpp | 20 +-- host/lib/usrp/usrp2/io_impl.cpp | 261 +++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 95 ++------------ host/lib/usrp/usrp2/usrp2_impl.hpp | 5 + 11 files changed, 299 insertions(+), 190 deletions(-) delete mode 100644 host/include/uhd/shared_iovec.hpp delete mode 100644 host/lib/shared_iovec.cpp create mode 100644 host/lib/usrp/usrp2/io_impl.cpp (limited to 'host/lib/transport') diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index e87f74291..f4fb96786 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,7 +26,6 @@ INSTALL(FILES gain_handler.hpp metadata.hpp props.hpp - shared_iovec.hpp time_spec.hpp utils.hpp wax.hpp diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index da58d4f85..596a98bc4 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -77,7 +77,7 @@ public: * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param the type of data loaded in the buffer (32fc, 16sc) - * \return the number of bytes sent + * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, @@ -91,7 +91,7 @@ public: * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param the type of data to fill into the buffer (32fc, 16sc) - * \return the number of bytes received + * \return the number of samples received */ virtual size_t recv( const boost::asio::mutable_buffer &buff, diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp index 43b91d1b0..70842e7bc 100644 --- a/host/include/uhd/metadata.hpp +++ b/host/include/uhd/metadata.hpp @@ -30,13 +30,17 @@ namespace uhd{ */ struct metadata_t{ uint32_t stream_id; + bool has_stream_id; time_spec_t time_spec; + bool has_time_spec; bool start_of_burst; bool end_of_burst; 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; } diff --git a/host/include/uhd/shared_iovec.hpp b/host/include/uhd/shared_iovec.hpp deleted file mode 100644 index a120e55d5..000000000 --- a/host/include/uhd/shared_iovec.hpp +++ /dev/null @@ -1,54 +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 . -// - -#ifndef INCLUDED_UHD_SHARED_IOVEC_HPP -#define INCLUDED_UHD_SHARED_IOVEC_HPP - -#include -#include - -namespace uhd{ - -/*! - * A shared iovec contains a shared array and its length. - * Creating a new shared iovec allocates new memory. - * This memory is freed when all copies are destroyed. - */ -class shared_iovec{ -public: - /*! - * Create a shared iovec and allocate memory. - * \param len the length in bytes - */ - shared_iovec(size_t len=0); - - /*! - * Destroy a shared iovec. - * Will not free the memory unless this is the last copy. - */ - ~shared_iovec(void); - - void *base; - size_t len; - -private: - boost::shared_array _shared_array; -}; - -} //namespace uhd - -#endif /* INCLUDED_UHD_SHARED_IOVEC_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp index 07d84e62a..8c6fb096f 100644 --- a/host/include/uhd/transport/udp.hpp +++ b/host/include/uhd/transport/udp.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP #define INCLUDED_UHD_TRANSPORT_UDP_HPP @@ -58,18 +57,18 @@ public: /*! * Receive a buffer. Write into the memory provided. * Returns empty when data is not available. - * \param buff a mutable buffer to receive into + * \param buffs a vector of asio buffers * \return the number of bytes received. */ - virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; + virtual size_t recv(const std::vector &buffs) = 0; /*! - * Receive a buffer. The memory is managed internally. - * Returns zero when data is not available. - * Calling recv will invalidate the buffer of the previous recv. - * \return a shared iovec with allocated memory + * Receive a buffer. Write into the memory provided. + * Returns empty when data is not available. + * \param buff a mutable buffer to receive into + * \return the number of bytes received. */ - virtual uhd::shared_iovec recv(void) = 0; + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; }; }} //namespace diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 5cf334678..253f45614 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -20,7 +20,6 @@ SET(libuhd_sources device.cpp device_addr.cpp gain_handler.cpp - shared_iovec.cpp uhd.cpp wax.cpp transport/udp.cpp @@ -32,6 +31,7 @@ SET(libuhd_sources usrp/usrp2/dboard_impl.cpp usrp/usrp2/dboard_interface.cpp usrp/usrp2/dsp_impl.cpp + usrp/usrp2/io_impl.cpp usrp/usrp2/mboard_impl.cpp usrp/usrp2/usrp2_impl.cpp ) diff --git a/host/lib/shared_iovec.cpp b/host/lib/shared_iovec.cpp deleted file mode 100644 index 60062fbf0..000000000 --- a/host/lib/shared_iovec.cpp +++ /dev/null @@ -1,28 +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 . -// - -#include - -uhd::shared_iovec::shared_iovec(size_t len_){ - _shared_array = boost::shared_array(new uint8_t[len_]); - base = _shared_array.get(); - len = len_; -} - -uhd::shared_iovec::~shared_iovec(void){ - /* NOP */ -} diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp index fca4dd7d6..878f71410 100644 --- a/host/lib/transport/udp.cpp +++ b/host/lib/transport/udp.cpp @@ -31,8 +31,8 @@ public: //send/recv size_t send(const std::vector &buffs); size_t send(const boost::asio::const_buffer &buff); + size_t recv(const std::vector &buffs); size_t recv(const boost::asio::mutable_buffer &buff); - uhd::shared_iovec recv(void); private: boost::asio::ip::udp::socket *_socket; @@ -87,20 +87,12 @@ size_t udp_impl::send(const boost::asio::const_buffer &buff){ return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); } -size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){ +size_t udp_impl::recv(const std::vector &buffs){ if (_socket->available() == 0) return 0; - return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); + return _socket->receive_from(buffs, _sender_endpoint); } -uhd::shared_iovec udp_impl::recv(void){ - //allocate a buffer for the number of bytes available (could be zero) - uhd::shared_iovec iov(_socket->available()); - //call recv only if data is available - if (iov.len != 0){ - _socket->receive_from( - boost::asio::buffer(iov.base, iov.len), - _sender_endpoint - ); - } - return iov; +size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp new file mode 100644 index 000000000..fbea71f85 --- /dev/null +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -0,0 +1,261 @@ +// +// 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 . +// + +#include +#include +#include +#include "usrp2_impl.hpp" + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Constants + **********************************************************************/ +typedef std::complex fc32_t; +typedef std::complex sc16_t; + +static const float float_scale_factor = pow(2.0, 15); + +//max length with header, stream id, seconds, fractional seconds +static const size_t max_vrt_header_words = 5; + +/*********************************************************************** + * Helper Functions + **********************************************************************/ + +/*static void pack_vrt_header( + size_t num_data_words, //input + const uhd::metadata_t &metadata, //input + uint32_t *vrt_header, //output + size_t &vrt_header_words //output +){ + // +} + +static void unpack_vrt_header( + size_t &num_data_words, //output + uhd::metadata_t &metadata, //output + const uint32_t *vrt_header, //input + size_t &vrt_header_words //output +){ + // +}*/ + +static inline void host_floats_to_usrp2_shorts( + int16_t *usrp2_shorts, + const float *host_floats, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + usrp2_shorts[i] = htons(int16_t(host_floats[i]*float_scale_factor)); + } +} + +static inline void usrp2_shorts_to_host_floats( + float *host_floats, + const int16_t *usrp2_shorts, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor); + } +} + +static inline void host_shorts_to_usrp2_shorts( + int16_t *usrp2_shorts, + const int16_t *host_shorts, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + usrp2_shorts[i] = htons(host_shorts[i]); + } +} + +static inline void usrp2_shorts_to_host_shorts( + int16_t *host_shorts, + const int16_t *usrp2_shorts, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + host_shorts[i] = ntohs(usrp2_shorts[i]); + } +} + +/*********************************************************************** + * Send Raw Data + **********************************************************************/ +size_t usrp2_impl::send_raw( + const boost::asio::const_buffer &buff, + const uhd::metadata_t &metadata +){ + std::vector buffs(2); + uint32_t vrt_hdr[max_vrt_header_words]; + uint32_t vrt_hdr_flags = 0; + size_t num_vrt_hdr_words = 1; + + //load the vrt header and flags + if(metadata.has_stream_id){ + vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier + vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.stream_id); + } + if(metadata.has_time_spec){ + vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp + vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.secs); + vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.ticks); + vrt_hdr[num_vrt_hdr_words++] = 0; //unused part of fractional seconds + } + vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; + vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + + //fill in complete header word + vrt_hdr[0] = htonl(vrt_hdr_flags | + ((_stream_id_to_packet_seq[metadata.stream_id]++ << 16) & 0xf) | + ((boost::asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff) + ); + + //load the buffer vector + size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t); + buffs[0] = boost::asio::buffer(&vrt_hdr, vrt_hdr_size); + buffs[1] = buff; + + //send and return number of samples + return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t); +} + +/*********************************************************************** + * Receive Raw Data + **********************************************************************/ +size_t usrp2_impl::recv_raw( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata +){ + //load the buffer vector + std::vector buffs(2); + uint32_t vrt_hdr[max_vrt_header_words]; + buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words); + buffs[1] = buff; + + //receive into the buffers + size_t bytes_recvd = _data_transport->recv(buffs); + + //failure case + if (bytes_recvd < max_vrt_header_words*sizeof(uint32_t)) return 0; + + //unpack the vrt header + metadata = uhd::metadata_t(); + uint32_t vrt_header = ntohl(vrt_hdr[0]); + metadata.has_stream_id = true; + metadata.stream_id = ntohl(vrt_hdr[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(vrt_hdr[2]); + metadata.time_spec.ticks = ntohl(vrt_hdr[3]); + + //return the number of samples received + size_t num_words = vrt_header & 0xffff; + return (num_words*sizeof(uint32_t))/sizeof(sc16_t); +} + +/*********************************************************************** + * Send Data + **********************************************************************/ +size_t usrp2_impl::send( + const boost::asio::const_buffer &buff, + const uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + boost::shared_array raw_mem(new sc16_t[num_samps]); + boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + + host_floats_to_usrp2_shorts( + boost::asio::buffer_cast(raw_buff), + boost::asio::buffer_cast(buff), + num_samps*2 //double for complex + ); + + return send_raw(raw_buff, metadata); + } + + if (type == "sc16"){ + #ifdef HAVE_BIG_ENDIAN + return send_raw(buff, metadata); + #else + size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + boost::shared_array raw_mem(new sc16_t[num_samps]); + boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + + host_shorts_to_usrp2_shorts( + boost::asio::buffer_cast(raw_buff), + boost::asio::buffer_cast(buff), + num_samps*2 //double for complex + ); + + return send_raw(raw_buff, metadata); + #endif + } + + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); +} + +/*********************************************************************** + * Receive Data + **********************************************************************/ +size_t usrp2_impl::recv( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + boost::shared_array raw_mem(new sc16_t[num_samps]); + boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + + num_samps = recv_raw(raw_buff, metadata); + + usrp2_shorts_to_host_floats( + boost::asio::buffer_cast(buff), + boost::asio::buffer_cast(raw_buff), + num_samps*2 //double for complex + ); + + return num_samps; + } + + if (type == "sc16"){ + #ifdef HAVE_BIG_ENDIAN + return recv_raw(buff, metadata); + #else + size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + boost::shared_array raw_mem(new sc16_t[num_samps]); + boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + + num_samps = recv_raw(raw_buff, metadata); + + usrp2_shorts_to_host_shorts( + boost::asio::buffer_cast(buff), + boost::asio::buffer_cast(raw_buff), + num_samps*2 //double for complex + ); + + return num_samps; + #endif + } + + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); +} diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 47bf06aff..11e2f480b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -44,19 +44,21 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //loop and recieve until the time is up size_t num_timeouts = 0; while(true){ - uhd::shared_iovec iov = udp_transport->recv(); - //std::cout << boost::asio::buffer_size(buff) << "\n"; - if (iov.len < sizeof(usrp2_ctrl_data_t)){ + usrp2_ctrl_data_t ctrl_data_in; + size_t len = udp_transport->recv( + boost::asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)) + ); + //std::cout << len << "\n"; + if (len < sizeof(usrp2_ctrl_data_t)){ //sleep a little so we dont burn cpu if (num_timeouts++ > 50) break; boost::this_thread::sleep(boost::posix_time::milliseconds(1)); }else{ //handle the received data - const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast(iov.base); - switch(ntohl(ctrl_data_in->id)){ + switch(ntohl(ctrl_data_in.id)){ case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: //make a boost asio ipv4 with the raw addr in host byte order - boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr)); + boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; new_addr["name"] = "USRP2"; new_addr["type"] = "udp"; @@ -161,14 +163,16 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da //loop and recieve until the time is up size_t num_timeouts = 0; while(true){ - uhd::shared_iovec iov = _ctrl_transport->recv(); - if (iov.len < sizeof(usrp2_ctrl_data_t)){ + usrp2_ctrl_data_t in_data; + size_t len = _ctrl_transport->recv( + boost::asio::buffer(&in_data, sizeof(in_data)) + ); + if (len < sizeof(usrp2_ctrl_data_t)){ //sleep a little so we dont burn cpu if (num_timeouts++ > 50) break; boost::this_thread::sleep(boost::posix_time::milliseconds(1)); }else{ //handle the received data - usrp2_ctrl_data_t in_data = *reinterpret_cast(iov.base); if (ntohl(in_data.seq) == _ctrl_seq_num){ return in_data; } @@ -204,76 +208,3 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ void usrp2_impl::set(const wax::obj &, const wax::obj &){ throw std::runtime_error("Cannot set in usrp2 device"); } - -/*********************************************************************** - * IO Interface - **********************************************************************/ -static const float float_scale_factor = pow(2.0, 15); - -size_t usrp2_impl::send( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata, - const std::string &type -){ - if (type == "fc32"){ - //extract the buffer elements - const float *float_buff = boost::asio::buffer_cast(buff); - const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); - - //convert floats into the shorts buffer - int16_t *shorts_buff = new int16_t[buff_len]; - for (size_t i = 0; i < buff_len; i++){ - shorts_buff[i] = float_buff[i]*float_scale_factor; - } - - //send from a buffer of shorts - size_t bytes_sent = send( - boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), - metadata, "sc16" - ); - - //cleanup - delete [] shorts_buff; - return bytes_sent; - } - - if (type == "sc16"){ - throw std::runtime_error("not implemented"); - } - - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); -} - -size_t usrp2_impl::recv( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata, - const std::string &type -){ - if (type == "fc32"){ - //extract the buffer elements - float *float_buff = boost::asio::buffer_cast(buff); - const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); - - //receive into a buffer of shorts - int16_t *shorts_buff = new int16_t[buff_len]; - size_t bytes_received = recv( - boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), - metadata, "sc16" - ); - - //convert floats into the shorts buffer - for (size_t i = 0; i < bytes_received/sizeof(int16_t); i++){ - float_buff[i] = shorts_buff[i]/float_scale_factor; - } - - //cleanup - delete [] shorts_buff; - return bytes_received; - } - - if (type == "sc16"){ - throw std::runtime_error("not implemented"); - } - - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); -} diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2476bcf1d..9a4c42d42 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -102,6 +102,11 @@ public: size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &); private: + //the raw io interface (samples are in the usrp2 native format) + size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); + size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); + uhd::dict _stream_id_to_packet_seq; + //udp transports for control and data uhd::transport::udp::sptr _ctrl_transport; uhd::transport::udp::sptr _data_transport; -- cgit v1.2.3 From 4efafcc2e20b9a980800a979edf5ea7a493b6462 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 2 Mar 2010 22:07:17 -0800 Subject: Expanded the UDP api: We can make simple udp transports for discovery and control. We can support a udp zero copy transport (currently just asio). Reworked the io_impl for usrp2 to work with the zero copy api. So far, all of this untested other than compiling. A cut-down vrt library is in the works to simplify the io impl. --- host/include/uhd/transport/CMakeLists.txt | 4 +- host/include/uhd/transport/smart_buffer.hpp | 45 ++++++ host/include/uhd/transport/udp.hpp | 76 ---------- host/include/uhd/transport/udp_simple.hpp | 79 +++++++++++ host/include/uhd/transport/udp_zero_copy.hpp | 76 ++++++++++ host/include/uhd/usrp/usrp2.hpp | 10 ++ host/lib/CMakeLists.txt | 9 +- host/lib/transport/udp.cpp | 98 ------------- host/lib/transport/udp_simple.cpp | 133 ++++++++++++++++++ host/lib/transport/udp_zero_copy_none.cpp | 117 ++++++++++++++++ host/lib/usrp/usrp2/io_impl.cpp | 202 +++++++++++---------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 18 ++- host/lib/usrp/usrp2/usrp2_impl.hpp | 24 ++-- 13 files changed, 577 insertions(+), 314 deletions(-) create mode 100644 host/include/uhd/transport/smart_buffer.hpp delete mode 100644 host/include/uhd/transport/udp.hpp create mode 100644 host/include/uhd/transport/udp_simple.hpp create mode 100644 host/include/uhd/transport/udp_zero_copy.hpp delete mode 100644 host/lib/transport/udp.cpp create mode 100644 host/lib/transport/udp_simple.cpp create mode 100644 host/lib/transport/udp_zero_copy_none.cpp (limited to 'host/lib/transport') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index b786eb945..ba8b33cc5 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -17,6 +17,8 @@ INSTALL(FILES - udp.hpp + smart_buffer.hpp + udp_simple.hpp + udp_zero_copy.hpp DESTINATION ${HEADER_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp new file mode 100644 index 000000000..914c02f50 --- /dev/null +++ b/host/include/uhd/transport/smart_buffer.hpp @@ -0,0 +1,45 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include + +#ifndef INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP +#define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP + +namespace uhd{ namespace transport{ + +/*! + * A buffer that knows how to free itself: + * + * This is just the smart buffer interface. + * A transport implementation will have its own + * internal (custom) smart buffer implementation. + * + * A smart buffer contains a boost asio const buffer. + * On destruction, the buffer contents will be freed. + */ +class smart_buffer : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + virtual const boost::asio::const_buffer &get(void) const = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp deleted file mode 100644 index 8c6fb096f..000000000 --- a/host/include/uhd/transport/udp.hpp +++ /dev/null @@ -1,76 +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 . -// - -#include -#include -#include - -#ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP -#define INCLUDED_UHD_TRANSPORT_UDP_HPP - -namespace uhd{ namespace transport{ - -class udp : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a new udp transport. - * The address will be resolved, it can be a host name or ipv4. - * The port will be resolved, it can be a port type or number. - * \param addr a string representing the destination address - * \param port a string representing the destination port - * \param bcast if true, enable the broadcast option on the socket - */ - static sptr make(const std::string &addr, const std::string &port, bool bcast = false); - - /*! - * Send a vector of buffer (like send_msg). - * Blocks until the data is sent. - * \param buffs a vector of asio buffers - * \return the number of bytes sent - */ - virtual size_t send(const std::vector &buffs) = 0; - - /*! - * Send a single buffer. - * Blocks until the data is sent. - * \param buff single asio buffer - * \return the number of bytes sent - */ - virtual size_t send(const boost::asio::const_buffer &buff) = 0; - - /*! - * Receive a buffer. Write into the memory provided. - * Returns empty when data is not available. - * \param buffs a vector of asio buffers - * \return the number of bytes received. - */ - virtual size_t recv(const std::vector &buffs) = 0; - - /*! - * Receive a buffer. Write into the memory provided. - * Returns empty when data is not available. - * \param buff a mutable buffer to receive into - * \return the number of bytes received. - */ - virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; -}; - -}} //namespace - -#endif /* INCLUDED_UHD_TRANSPORT_UDP_HPP */ diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp new file mode 100644 index 000000000..8663128ec --- /dev/null +++ b/host/include/uhd/transport/udp_simple.hpp @@ -0,0 +1,79 @@ +// +// 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 . +// + +#include +#include +#include + +#ifndef INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP +#define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP + +namespace uhd{ namespace transport{ + +class udp_simple : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new connected udp transport: + * This transport is for sending and receiving + * between this host and a single endpoint. + * The primary usage for this transport will be control transactions. + * The underlying implementation is simple and portable (not fast). + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make_connected(const std::string &addr, const std::string &port); + + /*! + * Make a new broadcasting udp transport: + * This transport can send udp broadcast datagrams + * and receive datagrams from multiple sources. + * The primary usage for this transport will be to discover devices. + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make_broadcast(const std::string &addr, const std::string &port); + + /*! + * Send a single buffer. + * Blocks until the data is sent. + * \param buff single asio buffer + * \return the number of bytes sent + */ + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + /*! + * Receive into the provided buffer. + * Returns empty when data is not available. + * \param buff a mutable buffer to receive into + * \return the number of bytes received. + */ + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP */ diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp new file mode 100644 index 000000000..9c3505dd6 --- /dev/null +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -0,0 +1,76 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include +#include + +#ifndef INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP +#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP + +namespace uhd{ namespace transport{ + +/*! + * A zero copy udp transport provides an efficient way to handle data. + * by avoiding the extra copy when recv() is called on the socket. + * Rather, the zero copy transport gives the caller a memory reference. + * The caller informs the transport when it is finished with the reference. + * + * On linux systems, the zero copy transport can use a kernel packet ring. + * If no platform specific solution is available, make returns a boost asio + * implementation that wraps the functionality around a standard recv() call. + */ +class udp_zero_copy : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new zero copy udp transport: + * This transport is for sending and receiving + * between this host and a single endpoint. + * The primary usage for this transport will be data transactions. + * The underlying implementation is fast and platform specific. + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make(const std::string &addr, const std::string &port); + + /*! + * Send a single buffer. + * Blocks until the data is sent. + * \param buff single asio buffer + * \return the number of bytes sent + */ + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + /*! + * Receive a buffer. + * The memory is managed by the implementation. + * Returns an empty buffer when data is not available. + * \return a smart buffer with memory and size + */ + virtual smart_buffer::sptr recv(void) = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP */ diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp index da7ec595a..b13786546 100644 --- a/host/include/uhd/usrp/usrp2.hpp +++ b/host/include/uhd/usrp/usrp2.hpp @@ -29,6 +29,11 @@ class usrp2 : public device{ public: /*! * Discover usrp2 devices over the ethernet. + * + * Recommended key/value pairs for the device hint address: + * hint["addr"] = address, where address is a resolvable address + * or ip address, which may or may not be a broadcast address. + * * This static method will be called by the device::discover. * \param hint a device addr with the usrp2 address filled in * \return a vector of device addresses for all usrp2s found @@ -37,6 +42,11 @@ public: /*! * Make a usrp2 from a device address. + * + * Required key/value pairs for the device address: + * hint["addr"] = address, where address is a resolvable address + * or ip address, which must be the specific address of a usrp2. + * * \param addr the device address * \return a device sptr to a new usrp2 */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 97f1ac52e..a52cd74a9 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,7 +23,7 @@ SET(libuhd_sources device_addr.cpp gain_handler.cpp wax.cpp - transport/udp.cpp + transport/udp_simple.cpp usrp/dboard/basic.cpp usrp/dboard_base.cpp usrp/dboard_id.cpp @@ -37,6 +37,13 @@ SET(libuhd_sources usrp/usrp2/usrp2_impl.cpp ) +######################################################################## +# Conditionally add the udp sources +######################################################################## +LIST(APPEND libuhd_sources + transport/udp_zero_copy_none.cpp +) + ######################################################################## # Conditionally add the usrp1e sources ######################################################################## diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp deleted file mode 100644 index 878f71410..000000000 --- a/host/lib/transport/udp.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include -#include -#include - -/*********************************************************************** - * UDP implementation class - **********************************************************************/ -class udp_impl : public uhd::transport::udp{ -public: - //structors - udp_impl(const std::string &addr, const std::string &port, bool bcast); - ~udp_impl(void); - - //send/recv - size_t send(const std::vector &buffs); - size_t send(const boost::asio::const_buffer &buff); - size_t recv(const std::vector &buffs); - size_t recv(const boost::asio::mutable_buffer &buff); - -private: - boost::asio::ip::udp::socket *_socket; - boost::asio::ip::udp::endpoint _receiver_endpoint; - boost::asio::ip::udp::endpoint _sender_endpoint; - boost::asio::io_service _io_service; -}; - -/*********************************************************************** - * UDP public make function - **********************************************************************/ -uhd::transport::udp::sptr uhd::transport::udp::make( - const std::string &addr, - const std::string &port, - bool bcast -){ - return uhd::transport::udp::sptr(new udp_impl(addr, port, bcast)); -} - -/*********************************************************************** - * UDP implementation methods - **********************************************************************/ -udp_impl::udp_impl(const std::string &addr, const std::string &port, bool bcast){ - //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; - - // resolve the address - boost::asio::ip::udp::resolver resolver(_io_service); - boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); - _receiver_endpoint = *resolver.resolve(query); - - // Create and open the socket - _socket = new boost::asio::ip::udp::socket(_io_service); - _socket->open(boost::asio::ip::udp::v4()); - - if (bcast){ - // Allow broadcasting - boost::asio::socket_base::broadcast option(true); - _socket->set_option(option); - } - -} - -udp_impl::~udp_impl(void){ - delete _socket; -} - -size_t udp_impl::send(const std::vector &buffs){ - return _socket->send_to(buffs, _receiver_endpoint); -} - -size_t udp_impl::send(const boost::asio::const_buffer &buff){ - return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); -} - -size_t udp_impl::recv(const std::vector &buffs){ - if (_socket->available() == 0) return 0; - return _socket->receive_from(buffs, _sender_endpoint); -} - -size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; - return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); -} diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp new file mode 100644 index 000000000..491cf59db --- /dev/null +++ b/host/lib/transport/udp_simple.cpp @@ -0,0 +1,133 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include + +using namespace uhd::transport; + +/*********************************************************************** + * UDP connected implementation class + **********************************************************************/ +class udp_connected_impl : public udp_simple{ +public: + //structors + udp_connected_impl(const std::string &addr, const std::string &port); + ~udp_connected_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::io_service _io_service; +}; + +udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); + boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); + + // Create, open, and connect the socket + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + _socket->connect(receiver_endpoint); +} + +udp_connected_impl::~udp_connected_impl(void){ + delete _socket; +} + +size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); +} + +size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + return _socket->receive(boost::asio::buffer(buff)); +} + +/*********************************************************************** + * UDP broadcast implementation class + **********************************************************************/ +class udp_broadcast_impl : public udp_simple{ +public: + //structors + udp_broadcast_impl(const std::string &addr, const std::string &port); + ~udp_broadcast_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::ip::udp::endpoint _receiver_endpoint; + boost::asio::io_service _io_service; +}; + +udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); + _receiver_endpoint = *resolver.resolve(query); + + // Create and open the socket + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + + // Allow broadcasting + boost::asio::socket_base::broadcast option(true); + _socket->set_option(option); + +} + +udp_broadcast_impl::~udp_broadcast_impl(void){ + delete _socket; +} + +size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); +} + +size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + boost::asio::ip::udp::endpoint sender_endpoint; + return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint); +} + +/*********************************************************************** + * UDP public make functions + **********************************************************************/ +udp_simple::sptr udp_simple::make_connected( + const std::string &addr, const std::string &port +){ + return sptr(new udp_connected_impl(addr, port)); +} + +udp_simple::sptr udp_simple::make_broadcast( + const std::string &addr, const std::string &port +){ + return sptr(new udp_broadcast_impl(addr, port)); +} diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp new file mode 100644 index 000000000..e95706d94 --- /dev/null +++ b/host/lib/transport/udp_zero_copy_none.cpp @@ -0,0 +1,117 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include + +using namespace uhd::transport; + +/*********************************************************************** + * Smart buffer implementation for udp zerocopy none + * + * This smart buffer implemention houses a const buffer. + * When the smart buffer is deleted, the buffer is freed. + * The memory in the const buffer is allocated with new [], + * and so the destructor frees the buffer with delete []. + **********************************************************************/ +class smart_buffer_impl : public smart_buffer{ +public: + smart_buffer_impl(const boost::asio::const_buffer &buff){ + _buff = buff; + } + + ~smart_buffer_impl(void){ + delete [] boost::asio::buffer_cast(_buff); + } + + const boost::asio::const_buffer &get(void) const{ + return _buff; + } + +private: + boost::asio::const_buffer _buff; +}; + +/*********************************************************************** + * UDP zero copy implementation class + * + * This is the portable zero copy implementation for systems + * where a faster, platform specific solution is not available. + * + * It uses boost asio udp sockets and the standard recv() class, + * and in-fact, is not actually doing a zero-copy implementation. + **********************************************************************/ +class udp_zero_copy_impl : public udp_zero_copy{ +public: + //structors + udp_zero_copy_impl(const std::string &addr, const std::string &port); + ~udp_zero_copy_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + smart_buffer::sptr recv(void); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::io_service _io_service; +}; + +udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); + boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); + + // Create, open, and connect the socket + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + _socket->connect(receiver_endpoint); +} + +udp_zero_copy_impl::~udp_zero_copy_impl(void){ + delete _socket; +} + +size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); +} + +smart_buffer::sptr udp_zero_copy_impl::recv(void){ + size_t available = _socket->available(); + + //allocate memory and create buffer + uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)]; + boost::asio::mutable_buffer buff(buff_mem, available); + + //receive only if data is available + if (available > 0){ + _socket->receive(boost::asio::buffer(buff)); + } + + //create a new smart buffer to house the data + return smart_buffer::sptr(new smart_buffer_impl(buff)); +} + +/*********************************************************************** + * UDP zero copy make function + **********************************************************************/ +udp_zero_copy::sptr udp_zero_copy::make( + const std::string &addr, const std::string &port +){ + return sptr(new udp_zero_copy_impl(addr, port)); +} diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 0ca2409c3..6969e0a89 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -36,12 +36,12 @@ static const float floats_per_short = 1.0/shorts_per_float; * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //initially empty spillover buffer - _splillover_buff = asio::buffer(_spillover_mem, 0); + //initially empty copy buffer + _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port uint32_t zero_data = 0; - _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data))); + _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); } #define unrolled_loop(__i, __len, __inst) {\ @@ -57,6 +57,13 @@ void usrp2_impl::io_init(void){ } \ } +// set a boolean flag that indicates the endianess +#ifdef HAVE_BIG_ENDIAN +static const bool is_big_endian = true; +#else +static const bool is_big_endian = false; +#endif + static inline void host_floats_to_usrp2_items( uint32_t *usrp2_items, const fc32_t *host_floats, @@ -87,9 +94,12 @@ static inline void host_items_to_usrp2_items( const uint32_t *host_items, size_t num_samps ){ - unrolled_loop(i, num_samps, - usrp2_items[i] = htonl(host_items[i]) - ); + if (is_big_endian){ + std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t)); + } + else{ + unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); + } } static inline void usrp2_items_to_host_items( @@ -97,20 +107,22 @@ static inline void usrp2_items_to_host_items( const uint32_t *usrp2_items, size_t num_samps ){ - unrolled_loop(i, num_samps, - host_items[i] = ntohl(usrp2_items[i]) - ); + if (is_big_endian){ + std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t)); + } + else{ + unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); + } } /*********************************************************************** * Send Raw Data **********************************************************************/ -size_t usrp2_impl::send_raw( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata -){ - std::vector buffs(2); - uint32_t vrt_hdr[7]; //max size +size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){ + size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t); + const uint32_t *items = asio::buffer_cast(_tx_copy_buff); + + uint32_t vrt_hdr[_tx_vrt_max_offset_words32]; uint32_t vrt_hdr_flags = 0; size_t num_vrt_hdr_words = 1; @@ -131,60 +143,30 @@ size_t usrp2_impl::send_raw( //fill in complete header word vrt_hdr[0] = htonl(vrt_hdr_flags | ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((num_vrt_hdr_words + asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff) + ((num_vrt_hdr_words + num_items) & 0xffff) ); - //load the buffer vector - size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t); - buffs[0] = asio::buffer(&vrt_hdr, vrt_hdr_size); - buffs[1] = buff; + //copy in the vrt header (yes we left space) + std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words); + asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t)); //send and return number of samples - return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t); + return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t); } /*********************************************************************** * Receive Raw Data **********************************************************************/ -size_t usrp2_impl::recv_raw( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata -){ - metadata = metadata_t(); //clear metadata - - //handle the case where there is spillover - if (asio::buffer_size(_splillover_buff) != 0){ - size_t bytes_to_copy = std::min( - asio::buffer_size(_splillover_buff), - asio::buffer_size(buff) - ); - std::memcpy( - asio::buffer_cast(buff), - asio::buffer_cast(_splillover_buff), - bytes_to_copy - ); - _splillover_buff = asio::buffer( - asio::buffer_cast(_splillover_buff)+bytes_to_copy, - asio::buffer_size(_splillover_buff)-bytes_to_copy - ); - //std::cout << boost::format("Copied spillover %d samples") % (bytes_to_copy/sizeof(sc16_t)) << std::endl; - return bytes_to_copy/sizeof(sc16_t); - } - - //load the buffer vector - std::vector buffs(3); - uint32_t vrt_hdr[USRP2_HOST_RX_VRT_HEADER_WORDS32]; - buffs[0] = asio::buffer(vrt_hdr, sizeof(vrt_hdr)); - buffs[1] = buff; - buffs[2] = asio::buffer(_spillover_mem, _mtu); +void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ + //do a receive + _rx_smart_buff = _data_transport->recv(); - //receive into the buffers - size_t bytes_recvd = _data_transport->recv(buffs); - - //failure case - if (bytes_recvd < sizeof(vrt_hdr)) return 0; + //////////////////////////////////////////////////////////////////// + // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!! + //////////////////////////////////////////////////////////////////// //unpack the vrt header + const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); metadata = uhd::metadata_t(); uint32_t vrt_header = ntohl(vrt_hdr[0]); metadata.has_stream_id = true; @@ -202,13 +184,12 @@ size_t usrp2_impl::recv_raw( size_t num_words = (vrt_header & 0xffff) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - USRP2_HOST_RX_VRT_TRAILER_WORDS32; - size_t num_bytes = num_words*sizeof(uint32_t); - - //handle the case where spillover memory was used - size_t spillover_size = num_bytes - std::min(num_bytes, asio::buffer_size(buff)); - _splillover_buff = asio::buffer(_spillover_mem, spillover_size); - return (num_bytes - spillover_size)/sizeof(sc16_t); + //setup the rx buffer to point to the data + _rx_copy_buff = boost::asio::buffer( + vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32, + num_words*sizeof(uint32_t) + ); } /*********************************************************************** @@ -219,37 +200,26 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - if (type == "32fc"){ - size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); + uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data + size_t num_samps = _max_samples_per_packet; - host_floats_to_usrp2_items( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps - ); - - return send_raw(raw_buff, metadata); + //calculate the number of samples to be copied + //and copy the samples into the send buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + host_floats_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); } - - if (type == "16sc"){ - #ifdef HAVE_BIG_ENDIAN - return send_raw(buff, metadata); - #else - size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); - - host_items_to_usrp2_items( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps - ); - - return send_raw(raw_buff, metadata); - #endif + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + host_items_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); + //send the samples (this line seems silly, will be better with vrt lib) + _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t)); + return send_raw(metadata); //return num_samps; } /*********************************************************************** @@ -260,39 +230,31 @@ size_t usrp2_impl::recv( uhd::metadata_t &metadata, const std::string &type ){ - if (type == "32fc"){ - size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); - - num_samps = recv_raw(raw_buff, metadata); + //perform a receive if no rx data is waiting to be copied + if (asio::buffer_size(_rx_copy_buff) == 0) recv_raw(metadata); + //TODO otherwise flag the metadata to show that is is a fragment - usrp2_items_to_host_floats( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps - ); + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t num_samps = asio::buffer_size(_rx_copy_buff)/sizeof(uint32_t); + const uint32_t *items = asio::buffer_cast(_rx_copy_buff); - return num_samps; + //calculate the number of samples to be copied + //and copy the samples from the recv buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + usrp2_items_to_host_floats(asio::buffer_cast(buff), items, num_samps); } - - if (type == "16sc"){ - #ifdef HAVE_BIG_ENDIAN - return recv_raw(buff, metadata); - #else - size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); - - num_samps = recv_raw(raw_buff, metadata); - - usrp2_items_to_host_items( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps - ); - - return num_samps; - #endif + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + usrp2_items_to_host_items(asio::buffer_cast(buff), items, num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); } - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); + //update the rx copy buffer to reflect the bytes copied + _rx_copy_buff = asio::buffer(items + num_samps, num_samps*sizeof(uint32_t)); + + return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 700f94ae1..51082df15 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -23,6 +23,7 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; /*********************************************************************** * Discovery over the udp transport @@ -33,8 +34,9 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //create a udp transport to communicate //TODO if an addr is not provided, search all interfaces? std::string ctrl_port = boost::lexical_cast(USRP2_UDP_CTRL_PORT); - transport::udp::sptr udp_transport = \ - transport::udp::make(hint["addr"], ctrl_port, true); + udp_simple::sptr udp_transport = udp_simple::make_broadcast( + hint["addr"], ctrl_port + ); //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; @@ -76,16 +78,18 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -#define num2str(num) (boost::lexical_cast(num)) +template std::string num2str(T num){ + return boost::lexical_cast(num); +} device::sptr usrp2::make(const device_addr_t &device_addr){ //create a control transport - transport::udp::sptr ctrl_transport = transport::udp::make( + udp_simple::sptr ctrl_transport = udp_simple::make_connected( device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) ); //create a data transport - transport::udp::sptr data_transport = transport::udp::make( + udp_zero_copy::sptr data_transport = udp_zero_copy::make( device_addr["addr"], num2str(USRP2_UDP_DATA_PORT) ); @@ -99,8 +103,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - transport::udp::sptr ctrl_transport, - transport::udp::sptr data_transport + udp_simple::sptr ctrl_transport, + udp_zero_copy::sptr data_transport ){ _ctrl_transport = ctrl_transport; _data_transport = data_transport; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 037aed477..a58bf8471 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include #include "fw_common.h" @@ -81,8 +82,8 @@ public: * \param data_transport the udp transport for data */ usrp2_impl( - uhd::transport::udp::sptr ctrl_transport, - uhd::transport::udp::sptr data_transport + uhd::transport::udp_simple::sptr ctrl_transport, + uhd::transport::udp_zero_copy::sptr data_transport ); ~usrp2_impl(void); @@ -103,8 +104,8 @@ public: private: //the raw io interface (samples are in the usrp2 native format) - size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); - size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); + size_t send_raw(const uhd::metadata_t &); + void recv_raw(uhd::metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea @@ -114,15 +115,16 @@ private: USRP2_HOST_RX_VRT_TRAILER_WORDS32 - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) ; - uint32_t _tmp_send_mem[_mtu/sizeof(uint32_t)]; - uint32_t _tmp_recv_mem[_mtu/sizeof(uint32_t)]; - uint32_t _spillover_mem[_mtu/sizeof(uint32_t)]; - boost::asio::mutable_buffer _splillover_buff; + static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib + uint32_t _tx_mem[_mtu/sizeof(uint32_t)]; + boost::asio::const_buffer _tx_copy_buff; + uhd::transport::smart_buffer::sptr _rx_smart_buff; + boost::asio::const_buffer _rx_copy_buff; void io_init(void); //udp transports for control and data - uhd::transport::udp::sptr _ctrl_transport; - uhd::transport::udp::sptr _data_transport; + uhd::transport::udp_simple::sptr _ctrl_transport; + uhd::transport::udp_zero_copy::sptr _data_transport; //private vars for dealing with send/recv control uint32_t _ctrl_seq_num; -- cgit v1.2.3 From 8e8221dc380fb275a17dcd0abbfaea108f44505f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 2 Mar 2010 23:56:19 -0800 Subject: Added a vrt library to pack and unpack from metadata. Added a vrt test app that packs and unpacks the data. --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/vrt.hpp | 66 +++++++++++++++++++ host/lib/CMakeLists.txt | 1 + host/lib/transport/vrt.cpp | 104 ++++++++++++++++++++++++++++++ host/test/CMakeLists.txt | 1 + host/test/vrt_test.cpp | 97 ++++++++++++++++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 host/include/uhd/transport/vrt.hpp create mode 100644 host/lib/transport/vrt.cpp create mode 100644 host/test/vrt_test.cpp (limited to 'host/lib/transport') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index ba8b33cc5..7f5db2128 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -20,5 +20,6 @@ INSTALL(FILES smart_buffer.hpp udp_simple.hpp udp_zero_copy.hpp + vrt.hpp DESTINATION ${HEADER_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp new file mode 100644 index 000000000..b56da4077 --- /dev/null +++ b/host/include/uhd/transport/vrt.hpp @@ -0,0 +1,66 @@ +// +// 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 . +// + +#include +#include + +#ifndef INCLUDED_UHD_TRANSPORT_VRT_HPP +#define INCLUDED_UHD_TRANSPORT_VRT_HPP + +namespace uhd{ namespace transport{ + +namespace vrt{ + + static const size_t max_header_words32 = 7; + + /*! + * Pack a vrt header from metadata. + * \param metadata the tx metadata with flags and timestamps + * \param header_buff memory to write the packed vrt header + * \param num_header_words32 number of words in the vrt header + * \param num_payload_words32 the length of the payload + * \param packet_count the packet count sequence number + */ + void pack( + const metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t packet_count //input + ); + + /*! + * Unpack a vrt header to metadata. + * \param metadata the rx metadata with flags and timestamps + * \param header_buff memory to read the packed vrt header + * \param num_header_words32 number of words in the vrt header + * \param num_payload_words32 the length of the payload + * \param packet_count the packet count sequence number + */ + void unpack( + metadata_t &metadata, //output + const uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t &packet_count //output + ); + +} //namespace vrt + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index a52cd74a9..390349906 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -24,6 +24,7 @@ SET(libuhd_sources gain_handler.cpp wax.cpp transport/udp_simple.cpp + transport/vrt.cpp usrp/dboard/basic.cpp usrp/dboard_base.cpp usrp/dboard_id.cpp diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp new file mode 100644 index 000000000..40b26d31f --- /dev/null +++ b/host/lib/transport/vrt.cpp @@ -0,0 +1,104 @@ +// +// 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 . +// + +#include +#include +#include + +using namespace uhd::transport; + +void vrt::pack( + const metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t packet_count //input +){ + uint32_t vrt_hdr_flags = 0; + num_header_words32 = 1; + + //load the vrt header and flags + if(metadata.has_stream_id){ + vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier + header_buff[num_header_words32++] = htonl(metadata.stream_id); + } + + if(metadata.has_time_spec){ + vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp + header_buff[num_header_words32++] = htonl(metadata.time_spec.secs); + header_buff[num_header_words32++] = htonl(metadata.time_spec.ticks); + header_buff[num_header_words32++] = 0; //unused part of fractional seconds + } + + vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; + vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + + //fill in complete header word + header_buff[0] = htonl(vrt_hdr_flags | + ((packet_count & 0xf) << 16) | + ((num_header_words32 + num_payload_words32) & 0xffff) + ); +} + +void vrt::unpack( + metadata_t &metadata, //output + const uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t &packet_count //output +){ + //clear the metadata + metadata = metadata_t(); + + //extract vrt header + uint32_t vrt_hdr_word = ntohl(header_buff[0]); + size_t packet_words32 = vrt_hdr_word & 0xffff; + packet_count = (vrt_hdr_word >> 16) & 0xf; + + //failure cases + if (packet_words32 == 0) //FIXME check the packet length before we continue + throw std::runtime_error("bad vrt header"); + if (vrt_hdr_word & (0x7 << 29)) + throw std::runtime_error("unsupported vrt packet type"); + + //parse the header flags + num_header_words32 = 1; + + if (vrt_hdr_word & (0x1 << 28)){ //stream id + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[num_header_words32++]); + } + + if (vrt_hdr_word & (0x1 << 27)){ //class id (we dont use) + num_header_words32 += 2; + } + + if (vrt_hdr_word & (0x3 << 22)){ //integer time + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[num_header_words32++]); + } + + if (vrt_hdr_word & (0x3 << 20)){ //fractional time + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[num_header_words32++]); + num_header_words32++; //unused part of fractional seconds + } + + size_t num_trailer_words32 = (vrt_hdr_word & (0x1 << 26))? 1 : 0; + + num_payload_words32 = packet_words32 - num_header_words32 - num_trailer_words32; +} diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt index 234b6f92c..b1d5924c7 100644 --- a/host/test/CMakeLists.txt +++ b/host/test/CMakeLists.txt @@ -20,6 +20,7 @@ ADD_EXECUTABLE(main_test main_test.cpp addr_test.cpp gain_handler_test.cpp + vrt_test.cpp wax_test.cpp ) diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp new file mode 100644 index 000000000..9b2d43430 --- /dev/null +++ b/host/test/vrt_test.cpp @@ -0,0 +1,97 @@ +// +// 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 . +// + +#include +#include + +using namespace uhd::transport; + +static void pack_and_unpack( + const uhd::metadata_t &metadata, + size_t num_payload_words32, + size_t packet_count +){ + uint32_t header_buff[vrt::max_header_words32]; + size_t num_header_words32; + + //pack metadata into a vrt header + vrt::pack( + metadata, //input + header_buff, //output + num_header_words32, //output + num_payload_words32, //input + packet_count //input + ); + + uhd::metadata_t metadata_out; + size_t num_header_words32_out; + size_t num_payload_words32_out; + size_t packet_count_out; + + //unpack the vrt header back into metadata + vrt::unpack( + metadata_out, //output + header_buff, //input + num_header_words32_out, //output + num_payload_words32_out, //output + packet_count_out //output + ); + + //check the the unpacked metadata is the same + BOOST_CHECK_EQUAL(packet_count, packet_count_out); + BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out); + BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out); + BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id); + if (metadata.has_stream_id and metadata_out.has_stream_id){ + BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id); + } + BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec); + if (metadata.has_time_spec and metadata_out.has_time_spec){ + BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs); + BOOST_CHECK_EQUAL(metadata.time_spec.ticks, metadata_out.time_spec.ticks); + } +} + +BOOST_AUTO_TEST_CASE(test_with_none){ + uhd::metadata_t metadata; + pack_and_unpack(metadata, 300, 1); +} + +BOOST_AUTO_TEST_CASE(test_with_sid){ + uhd::metadata_t metadata; + metadata.has_stream_id = true; + metadata.stream_id = 6; + pack_and_unpack(metadata, 400, 2); +} + +BOOST_AUTO_TEST_CASE(test_with_time_spec){ + uhd::metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec.secs = 7; + metadata.time_spec.ticks = 2000; + pack_and_unpack(metadata, 500, 3); +} + +BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ + uhd::metadata_t metadata; + metadata.has_stream_id = true; + metadata.stream_id = 2; + metadata.has_time_spec = true; + metadata.time_spec.secs = 5; + metadata.time_spec.ticks = 1000; + pack_and_unpack(metadata, 600, 4); +} -- cgit v1.2.3 From bb8417526c14bd49192c159cbdc52f5ea0063784 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 01:19:00 -0800 Subject: Making use of vrt lib in the usrp2 io_impl. Added a packet size param to the vrt pack and unpack. --- host/apps/discover_usrps.cpp | 1 + host/include/uhd/transport/vrt.hpp | 4 ++ host/lib/transport/vrt.cpp | 10 +++- host/lib/usrp/usrp2/dsp_impl.cpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 115 ++++++++++++++++--------------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 17 +++--- host/test/vrt_test.cpp | 3 + 8 files changed, 76 insertions(+), 80 deletions(-) (limited to 'host/lib/transport') diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 20ac1f9ed..448095726 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,6 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; + //uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index b56da4077..2fb90a497 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -33,6 +33,7 @@ namespace vrt{ * \param header_buff memory to write the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void pack( @@ -40,6 +41,7 @@ namespace vrt{ uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ); @@ -49,6 +51,7 @@ namespace vrt{ * \param header_buff memory to read the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void unpack( @@ -56,6 +59,7 @@ namespace vrt{ const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ); diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 40b26d31f..19bfc1d19 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -26,6 +26,7 @@ void vrt::pack( uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ){ uint32_t vrt_hdr_flags = 0; @@ -47,10 +48,12 @@ void vrt::pack( vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + num_packet_words32 = num_header_words32 + num_payload_words32; + //fill in complete header word header_buff[0] = htonl(vrt_hdr_flags | ((packet_count & 0xf) << 16) | - ((num_header_words32 + num_payload_words32) & 0xffff) + (num_packet_words32 & 0xffff) ); } @@ -59,6 +62,7 @@ void vrt::unpack( const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ){ //clear the metadata @@ -70,8 +74,8 @@ void vrt::unpack( packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0) //FIXME check the packet length before we continue - throw std::runtime_error("bad vrt header"); + if (packet_words32 == 0 or num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 8fdfd685f..a32f68872 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -82,7 +82,7 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); - out_data.data.streaming.samples = htonl(_max_samples_per_packet); + out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6969e0a89..9299bb04a 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -21,6 +21,7 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; namespace asio = boost::asio; /*********************************************************************** @@ -115,45 +116,6 @@ static inline void usrp2_items_to_host_items( } } -/*********************************************************************** - * Send Raw Data - **********************************************************************/ -size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){ - size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t); - const uint32_t *items = asio::buffer_cast(_tx_copy_buff); - - uint32_t vrt_hdr[_tx_vrt_max_offset_words32]; - uint32_t vrt_hdr_flags = 0; - size_t num_vrt_hdr_words = 1; - - //load the vrt header and flags - if(metadata.has_stream_id){ - vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.stream_id); - } - if(metadata.has_time_spec){ - vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.secs); - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.ticks); - vrt_hdr[num_vrt_hdr_words++] = 0; //unused part of fractional seconds - } - vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; - vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; - - //fill in complete header word - vrt_hdr[0] = htonl(vrt_hdr_flags | - ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((num_vrt_hdr_words + num_items) & 0xffff) - ); - - //copy in the vrt header (yes we left space) - std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words); - asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t)); - - //send and return number of samples - return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t); -} - /*********************************************************************** * Receive Raw Data **********************************************************************/ @@ -161,34 +123,37 @@ void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ //do a receive _rx_smart_buff = _data_transport->recv(); - //////////////////////////////////////////////////////////////////// - // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!! - //////////////////////////////////////////////////////////////////// - //unpack the vrt header const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); - metadata = uhd::metadata_t(); - uint32_t vrt_header = ntohl(vrt_hdr[0]); - metadata.has_stream_id = true; - metadata.stream_id = ntohl(vrt_hdr[1]); - metadata.has_time_spec = true; - metadata.time_spec.secs = ntohl(vrt_hdr[2]); - metadata.time_spec.ticks = ntohl(vrt_hdr[3]); - - size_t my_seq = (vrt_header >> 16) & 0xf; - //std::cout << "seq " << my_seq << std::endl; - if (my_seq != ((_rx_stream_id_to_packet_seq[metadata.stream_id]+1) & 0xf)) std::cout << "bad seq " << my_seq << std::endl; - _rx_stream_id_to_packet_seq[metadata.stream_id] = my_seq; + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t); + size_t num_header_words32_out; + size_t num_payload_words32_out; + size_t 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 + ); + }catch(const std::exception &e){ + std::cerr << "bad vrt header: " << e.what() << std::endl; + _rx_copy_buff = boost::asio::buffer("", 0); + } - //extract the number of bytes received - size_t num_words = (vrt_header & 0xffff) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32; + //handle the packet count / sequence number + size_t last_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != (last_packet_count+1)%16){ + std::cerr << "bad packet count: " << packet_count_out << std::endl; + } + _rx_stream_id_to_packet_seq[metadata.stream_id] = packet_count_out; //setup the rx buffer to point to the data _rx_copy_buff = boost::asio::buffer( - vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32, - num_words*sizeof(uint32_t) + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(uint32_t) ); } @@ -200,8 +165,9 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data - size_t num_samps = _max_samples_per_packet; + uint32_t tx_mem[_mtu/sizeof(uint32_t)]; + uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data + size_t num_samps = _max_tx_samples_per_packet; //calculate the number of samples to be copied //and copy the samples into the send buffer @@ -217,9 +183,26 @@ size_t usrp2_impl::send( throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - //send the samples (this line seems silly, will be better with vrt lib) - _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t)); - return send_raw(metadata); //return num_samps; + uint32_t vrt_hdr[vrt::max_header_words32]; + 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 + vrt_hdr, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count //input + ); + + //copy in the vrt header (yes we left space) + std::memcpy(items - num_header_words32, vrt_hdr, num_header_words32); + asio::const_buffer send_buff(items - num_header_words32, num_packet_words32*sizeof(uint32_t)); + + //send and return number of samples + _data_transport->send(send_buff); return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 51082df15..752feb05b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -209,11 +209,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_rx_samples_per_packet); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_tx_samples_per_packet); return; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index a58bf8471..083ad7096 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,20 +105,20 @@ public: private: //the raw io interface (samples are in the usrp2 native format) - size_t send_raw(const uhd::metadata_t &); void recv_raw(uhd::metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea - static const size_t _max_samples_per_packet = - _mtu/sizeof(uint32_t) - + 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(uint32_t) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 - - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) + USRP2_HOST_RX_VRT_TRAILER_WORDS32 + ; + static const size_t _max_tx_samples_per_packet = + (_mtu - _hdrs)/sizeof(uint32_t) - + uhd::transport::vrt::max_header_words32 ; - static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib - uint32_t _tx_mem[_mtu/sizeof(uint32_t)]; - boost::asio::const_buffer _tx_copy_buff; uhd::transport::smart_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; void io_init(void); diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 9b2d43430..a4fad78fc 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -27,6 +27,7 @@ static void pack_and_unpack( ){ uint32_t header_buff[vrt::max_header_words32]; size_t num_header_words32; + size_t num_packet_words32; //pack metadata into a vrt header vrt::pack( @@ -34,6 +35,7 @@ static void pack_and_unpack( header_buff, //output num_header_words32, //output num_payload_words32, //input + num_packet_words32, //output packet_count //input ); @@ -48,6 +50,7 @@ static void pack_and_unpack( header_buff, //input num_header_words32_out, //output num_payload_words32_out, //output + num_packet_words32, //input packet_count_out //output ); -- cgit v1.2.3 From ccd2665a29af046b0b8a11c48ffbfe2ed36ce8d9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 11:28:32 -0800 Subject: Split metadata into rx and tx specific metadata. The rx metadata has fragment flags and the tx metatdata has burst flags. Made the io impl for usrp2 rx routine fill in the rx metatdata fragment flag. Added device documentation for send and recv in regards to fragmentation. --- host/include/uhd/device.hpp | 21 +++++++++++++++++++-- host/include/uhd/metadata.hpp | 31 ++++++++++++++++++++----------- host/include/uhd/transport/vrt.hpp | 14 +++++++------- host/lib/CMakeLists.txt | 1 + host/lib/metadata.cpp | 37 +++++++++++++++++++++++++++++++++++++ host/lib/transport/vrt.cpp | 16 ++++++++-------- host/lib/usrp/usrp2/io_impl.cpp | 20 +++++++++++++------- host/lib/usrp/usrp2/usrp2_impl.hpp | 6 +++--- host/test/vrt_test.cpp | 12 ++++++------ 9 files changed, 114 insertions(+), 44 deletions(-) create mode 100644 host/lib/metadata.cpp (limited to 'host/lib/transport') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ba5337d33..1a52867c9 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -70,6 +70,13 @@ public: /*! * 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. + * It is up to the caller to call send again on the un-sent + * portions of the buffer, until the buffer is exhausted. + * * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param the type of data loaded in the buffer (32fc, 16sc) @@ -77,13 +84,23 @@ public: */ virtual size_t send( const boost::asio::const_buffer &buff, - const metadata_t &metadata, + const tx_metadata_t &metadata, const std::string &type = "32fc" ) = 0; /*! * Receive a buffer containing IF data and its metadata. * + * Receive handles fragmentation as follows: + * If the buffer has insufficient space to hold all samples + * that were received in a single packet over-the-wire, + * then the buffer will be completely filled and the implementation + * will hold a pointer into the remaining portion of the packet. + * Subsequent calls will load from the remainder of the packet, + * and will flag the metadata to show that this is a fragment. + * The next call to receive, after the remainder becomes exahausted, + * will perform an over-the-wire receive as usual. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param the type of data to fill into the buffer (32fc, 16sc) @@ -91,7 +108,7 @@ public: */ virtual size_t recv( const boost::asio::mutable_buffer &buff, - metadata_t &metadata, + rx_metadata_t &metadata, const std::string &type = "32fc" ) = 0; }; diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp index 70842e7bc..0588ef0ed 100644 --- a/host/include/uhd/metadata.hpp +++ b/host/include/uhd/metadata.hpp @@ -23,12 +23,27 @@ namespace uhd{ /*! - * Metadata structure for describing the IF data. - * Includes stream ID, time specification, and burst flags. + * RX metadata structure for describing sent IF data. + * Includes stream ID, time specification, and fragmentation flags. * The receive routines will convert IF data headers into metadata. + */ +struct rx_metadata_t{ + uint32_t stream_id; + bool has_stream_id; + time_spec_t time_spec; + bool has_time_spec; + bool is_fragment; + + //default constructor + rx_metadata_t(void); +}; + +/*! + * TX metadata structure for describing received IF data. + * Includes stream ID, time specification, and burst flags. * The send routines will convert the metadata to IF data headers. */ -struct metadata_t{ +struct tx_metadata_t{ uint32_t stream_id; bool has_stream_id; time_spec_t time_spec; @@ -36,14 +51,8 @@ struct metadata_t{ bool start_of_burst; bool end_of_burst; - 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; - } + //default constructor + tx_metadata_t(void); }; } //namespace uhd diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index 2fb90a497..1700d2785 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -37,12 +37,12 @@ namespace vrt{ * \param packet_count the packet count sequence number */ void pack( - const metadata_t &metadata, //input - uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count //input + const tx_metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t &num_packet_words32, //output + size_t packet_count //input ); /*! @@ -55,7 +55,7 @@ namespace vrt{ * \param packet_count the packet count sequence number */ void unpack( - metadata_t &metadata, //output + rx_metadata_t &metadata, //output const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 390349906..b1daf22d1 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -22,6 +22,7 @@ SET(libuhd_sources device.cpp device_addr.cpp gain_handler.cpp + metadata.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp diff --git a/host/lib/metadata.cpp b/host/lib/metadata.cpp new file mode 100644 index 000000000..40fdb7c73 --- /dev/null +++ b/host/lib/metadata.cpp @@ -0,0 +1,37 @@ +// +// 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 . +// + +#include + +using namespace uhd; + +rx_metadata_t::rx_metadata_t(void){ + stream_id = 0; + has_stream_id = false; + time_spec = time_spec_t(); + has_time_spec = false; + is_fragment = false; +} + +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; +} diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 19bfc1d19..5029df217 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -22,12 +22,12 @@ using namespace uhd::transport; void vrt::pack( - const metadata_t &metadata, //input - uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count //input + const tx_metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t &num_packet_words32, //output + size_t packet_count //input ){ uint32_t vrt_hdr_flags = 0; num_header_words32 = 1; @@ -58,7 +58,7 @@ void vrt::pack( } void vrt::unpack( - metadata_t &metadata, //output + rx_metadata_t &metadata, //output const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output @@ -66,7 +66,7 @@ void vrt::unpack( size_t &packet_count //output ){ //clear the metadata - metadata = metadata_t(); + metadata = rx_metadata_t(); //extract vrt header uint32_t vrt_hdr_word = ntohl(header_buff[0]); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 642b6b08b..5529cfe57 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -119,7 +119,7 @@ static inline void usrp2_items_to_host_items( /*********************************************************************** * Receive Raw Data **********************************************************************/ -void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ +void usrp2_impl::recv_raw(rx_metadata_t &metadata){ //do a receive _rx_smart_buff = _data_transport->recv(); @@ -161,8 +161,8 @@ void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ * Send Data **********************************************************************/ size_t usrp2_impl::send( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata, + const asio::const_buffer &buff, + const tx_metadata_t &metadata, const std::string &type ){ uint32_t tx_mem[_mtu/sizeof(uint32_t)]; @@ -210,13 +210,19 @@ size_t usrp2_impl::send( * Receive Data **********************************************************************/ size_t usrp2_impl::recv( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata, + const asio::mutable_buffer &buff, + rx_metadata_t &metadata, const std::string &type ){ //perform a receive if no rx data is waiting to be copied - if (asio::buffer_size(_rx_copy_buff) == 0) recv_raw(metadata); - //TODO otherwise flag the metadata to show that is is a fragment + if (asio::buffer_size(_rx_copy_buff) == 0){ + recv_raw(metadata); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = rx_metadata_t(); + metadata.is_fragment = true; + } //extract the number of samples available to copy //and a pointer into the usrp2 received items memory diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 083ad7096..f4e6054bd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -100,12 +100,12 @@ public: double get_master_clock_freq(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::metadata_t &, const std::string &); - size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &); + size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &); + size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); private: //the raw io interface (samples are in the usrp2 native format) - void recv_raw(uhd::metadata_t &); + void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index a4fad78fc..d80908c74 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -21,7 +21,7 @@ using namespace uhd::transport; static void pack_and_unpack( - const uhd::metadata_t &metadata, + const uhd::tx_metadata_t &metadata, size_t num_payload_words32, size_t packet_count ){ @@ -39,7 +39,7 @@ static void pack_and_unpack( packet_count //input ); - uhd::metadata_t metadata_out; + uhd::rx_metadata_t metadata_out; size_t num_header_words32_out; size_t num_payload_words32_out; size_t packet_count_out; @@ -70,19 +70,19 @@ static void pack_and_unpack( } BOOST_AUTO_TEST_CASE(test_with_none){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; pack_and_unpack(metadata, 300, 1); } BOOST_AUTO_TEST_CASE(test_with_sid){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_stream_id = true; metadata.stream_id = 6; pack_and_unpack(metadata, 400, 2); } BOOST_AUTO_TEST_CASE(test_with_time_spec){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_time_spec = true; metadata.time_spec.secs = 7; metadata.time_spec.ticks = 2000; @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(test_with_time_spec){ } BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_stream_id = true; metadata.stream_id = 2; metadata.has_time_spec = true; -- cgit v1.2.3 From bb86022d5a5f7055cdeebaeb4a55216e1a056fd4 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 4 Mar 2010 18:34:28 -0800 Subject: Moved timeouts into the udp transports. Simplified the fast path checking in the fw, but it turns out this was not the issue. Fixed some bad bit operations with the 16sc words (dont forget sign extension). Added some more documentation to the headers.... --- firmware/microblaze/apps/txrx.c | 16 ++++++++---- firmware/microblaze/lib/net_common.c | 11 -------- firmware/microblaze/lib/net_common.h | 2 -- host/include/uhd/device.hpp | 11 ++++++++ host/include/uhd/transport/udp_simple.hpp | 4 +-- host/include/uhd/transport/udp_zero_copy.hpp | 4 +-- host/lib/transport/udp_simple.cpp | 29 +++++++++++++++++++-- host/lib/transport/udp_zero_copy_none.cpp | 39 ++++++++++++++++++++++++++-- host/lib/usrp/usrp2/dsp_impl.cpp | 9 ++++--- host/lib/usrp/usrp2/io_impl.cpp | 14 +++++----- host/lib/usrp/usrp2/usrp2_impl.cpp | 39 ++++++++++------------------ 11 files changed, 115 insertions(+), 63 deletions(-) (limited to 'host/lib/transport') diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 9c3caa4f2..1b3299150 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -504,16 +504,22 @@ void handle_udp_ctrl_packet( static bool eth_pkt_inspector(dbsm_t *sm, int bufno) { - //extract buffer point and length + //point me to the ethernet frame uint32_t *buff = (uint32_t *)buffer_ram(bufno); - size_t len = buffer_pool_status->last_line[bufno] - 3; //treat this as fast-path data? - if (is_udp_packet_with_vrt(buff, len, USRP2_UDP_DATA_PORT)){ - return false; - } + // We have to do this operation as fast as possible. + // Therefore, we do not check all the headers, + // just check that the udp port matches + // and that the vrt header is non zero. + // In the future, a hardware state machine will do this... + if ( //warning! magic numbers approaching.... + (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && + ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != 0) + ) return false; //pass it to the slow-path handler + size_t len = buffer_pool_status->last_line[bufno] - 3; handle_eth_packet(buff, len); return true; } diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c index ab7aadca9..693502d18 100644 --- a/firmware/microblaze/lib/net_common.c +++ b/firmware/microblaze/lib/net_common.c @@ -378,17 +378,6 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) } } -bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port){ - struct ip_hdr *ip = (struct ip_hdr *)(p + 4); - struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); - uint32_t *payload = (uint32_t *)(((char *)udp) + UDP_HLEN); - return \ - (p[3] & 0xffff) == ETHERTYPE_IPV4 && - IPH_PROTO(ip) == IP_PROTO_UDP && - udp->dest == port && - payload[0] != 0; //must be non zero vrt header -} - void handle_eth_packet(uint32_t *p, size_t nlines) { diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h index 1a7052f71..6cd45bf69 100644 --- a/firmware/microblaze/lib/net_common.h +++ b/firmware/microblaze/lib/net_common.h @@ -56,6 +56,4 @@ void send_udp_pkt(int src_port, struct socket_address dst, void handle_eth_packet(uint32_t *p, size_t nlines); -bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port); - #endif /* INCLUDED_NET_COMMON_H */ diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 1a52867c9..47dfa4328 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -77,6 +77,9 @@ public: * It is up to the caller to call send again on the un-sent * portions of the buffer, until the buffer is exhausted. * + * This is a blocking call and will not return until the number + * of samples returned have been read out of the buffer. + * * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param the type of data loaded in the buffer (32fc, 16sc) @@ -101,6 +104,14 @@ public: * The next call to receive, after the remainder becomes exahausted, * will perform an over-the-wire receive as usual. * + * This is a blocking call and will not return until the number + * of samples returned have been written into the buffer. + * However, a call to receive may timeout and return zero samples. + * The timeout duration is decided by the underlying transport layer. + * The caller should assume that the call to receive will not return + * immediately when no packets are available to the transport layer, + * and that the timeout duration is reasonably tuned for performance. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param the type of data to fill into the buffer (32fc, 16sc) diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp index 8663128ec..0d8fcc5f0 100644 --- a/host/include/uhd/transport/udp_simple.hpp +++ b/host/include/uhd/transport/udp_simple.hpp @@ -67,9 +67,9 @@ public: /*! * Receive into the provided buffer. - * Returns empty when data is not available. + * Blocks until data is received or a timeout occurs. * \param buff a mutable buffer to receive into - * \return the number of bytes received. + * \return the number of bytes received or zero on timeout */ virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; }; diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 9c3505dd6..1a8d822fd 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -64,9 +64,9 @@ public: /*! * Receive a buffer. + * Blocks until data is received or a timeout occurs. * The memory is managed by the implementation. - * Returns an empty buffer when data is not available. - * \return a smart buffer with memory and size + * \return a smart buffer (empty on timeout) */ virtual smart_buffer::sptr recv(void) = 0; }; diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 491cf59db..7004bdfdf 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -16,11 +16,34 @@ // #include +#include #include #include using namespace uhd::transport; +/*********************************************************************** + * Helper Functions + **********************************************************************/ +/*! + * A receive timeout for a socket: + * + * It seems that asio cannot have timeouts with synchronous io. + * However, we can implement a polling loop that will timeout. + * This is okay bacause this is the slow-path implementation. + * + * \param socket the asio socket + */ +static void reasonable_recv_timeout( + boost::asio::ip::udp::socket &socket +){ + boost::asio::deadline_timer timer(socket.get_io_service()); + timer.expires_from_now(boost::posix_time::milliseconds(50)); + while (not (socket.available() or timer.expires_from_now().is_negative())){ + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } +} + /*********************************************************************** * UDP connected implementation class **********************************************************************/ @@ -62,7 +85,8 @@ size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){ } size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; + reasonable_recv_timeout(*_socket); + if (not _socket->available()) return 0; return _socket->receive(boost::asio::buffer(buff)); } @@ -112,7 +136,8 @@ size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){ } size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; + reasonable_recv_timeout(*_socket); + if (not _socket->available()) return 0; boost::asio::ip::udp::endpoint sender_endpoint; return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint); } diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp index e95706d94..e29530cf1 100644 --- a/host/lib/transport/udp_zero_copy_none.cpp +++ b/host/lib/transport/udp_zero_copy_none.cpp @@ -16,6 +16,8 @@ // #include +#include +#include using namespace uhd::transport; @@ -67,6 +69,9 @@ public: private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; + + size_t get_recv_buff_size(void); + void set_recv_buff_size(size_t); }; udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -81,6 +86,18 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin _socket = new boost::asio::ip::udp::socket(_io_service); _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); + + // set the rx socket buffer size: + // pick a huge size, and deal with whatever we get + set_recv_buff_size(54321e3); //some big number! + size_t current_buff_size = get_recv_buff_size(); + std::cout << boost::format( + "Current rx socket buffer size: %d\n" + ) % current_buff_size; + if (current_buff_size < .1e6) std::cout << boost::format( + "Adjust max rx socket buffer size (linux only):\n" + " sysctl -w net.core.rmem_max=VALUE\n" + ); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -92,14 +109,21 @@ size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ } smart_buffer::sptr udp_zero_copy_impl::recv(void){ - size_t available = _socket->available(); + size_t available = 0; + + //implement timeout through polling and sleeping + boost::asio::deadline_timer timer(_socket->get_io_service()); + timer.expires_from_now(boost::posix_time::milliseconds(50)); + while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } //allocate memory and create buffer uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)]; boost::asio::mutable_buffer buff(buff_mem, available); //receive only if data is available - if (available > 0){ + if (available){ _socket->receive(boost::asio::buffer(buff)); } @@ -107,6 +131,17 @@ smart_buffer::sptr udp_zero_copy_impl::recv(void){ return smart_buffer::sptr(new smart_buffer_impl(buff)); } +size_t udp_zero_copy_impl::get_recv_buff_size(void){ + boost::asio::socket_base::receive_buffer_size option; + _socket->get_option(option); + return option.value(); +} + +void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){ + boost::asio::socket_base::receive_buffer_size option(new_size); + _socket->set_option(option); +} + /*********************************************************************** * UDP zero copy make function **********************************************************************/ diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index a32f68872..7831b7667 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -21,6 +21,9 @@ using namespace uhd; +static const size_t default_decim = 16; +static const size_t default_interp = 16; + /*********************************************************************** * DDC Helper Methods **********************************************************************/ @@ -37,7 +40,7 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t } static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){ - return ((i & 0xffff) << 16) | ((q & 0xffff) << 0); + return (uint16_t(i) << 16) | (uint16_t(q) << 0); } void usrp2_impl::init_ddc_config(void){ @@ -48,7 +51,7 @@ void usrp2_impl::init_ddc_config(void){ ); //initial config and update - _ddc_decim = 64; + _ddc_decim = default_decim; _ddc_freq = 0; update_ddc_config(); @@ -196,7 +199,7 @@ void usrp2_impl::init_duc_config(void){ ); //initial config and update - _duc_interp = 64; + _duc_interp = default_interp; _duc_freq = 0; update_duc_config(); } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6273846dc..cc7746720 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -71,9 +71,9 @@ static inline void host_floats_to_usrp2_items( size_t num_samps ){ unrolled_loop(i, num_samps,{ - int16_t real = host_floats[i].real()*shorts_per_float; - int16_t imag = host_floats[i].imag()*shorts_per_float; - usrp2_items[i] = htonl(((real << 16) & 0xffff) | ((imag << 0) & 0xffff)); + uint16_t real = host_floats[i].real()*shorts_per_float; + uint16_t imag = host_floats[i].imag()*shorts_per_float; + usrp2_items[i] = htonl((real << 16) | (imag << 0)); }); } @@ -84,8 +84,8 @@ static inline void usrp2_items_to_host_floats( ){ unrolled_loop(i, num_samps,{ uint32_t item = ntohl(usrp2_items[i]); - int16_t real = (item >> 16) & 0xffff; - int16_t imag = (item >> 0) & 0xffff; + int16_t real = item >> 16; + int16_t imag = item >> 0; host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short); }); } @@ -130,9 +130,7 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ return; //must exit here after setting the buffer } const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); - size_t num_header_words32_out; - size_t num_payload_words32_out; - size_t packet_count_out; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; try{ vrt::unpack( metadata, //output diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 752feb05b..58c82303f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -24,6 +24,7 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +namespace asio = boost::asio; /*********************************************************************** * Discovery over the udp transport @@ -43,19 +44,12 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop and recieve until the timeout while(true){ usrp2_ctrl_data_t ctrl_data_in; - size_t len = udp_transport->recv( - boost::asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)) - ); + size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in))); //std::cout << len << "\n"; - if (len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ + if (len >= sizeof(usrp2_ctrl_data_t)){ //handle the received data switch(ntohl(ctrl_data_in.id)){ case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: @@ -67,9 +61,11 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); - break; + //dont break here, it will exit the while loop + //just continue on to the next loop iteration } } + if (len == 0) break; //timeout } return usrp2_addrs; @@ -164,24 +160,15 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da out_copy.seq = htonl(++_ctrl_seq_num); _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop until we get the packet or timeout while(true){ usrp2_ctrl_data_t in_data; - size_t len = _ctrl_transport->recv( - boost::asio::buffer(&in_data, sizeof(in_data)) - ); - if (len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ - //handle the received data - if (ntohl(in_data.seq) == _ctrl_seq_num){ - return in_data; - } - //didnt get seq, continue on... + size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data))); + if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){ + return in_data; } + if (len == 0) break; //timeout + //didnt get seq or bad packet, continue looking... } throw std::runtime_error("usrp2 no control response"); } -- cgit v1.2.3 From 6458eca9540f11fb8dd5bee184e6124998023c4f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 16 Mar 2010 17:54:54 -0700 Subject: Added recovery app to use raw socket to burn known ip addr. Fixed up fw so the device can reply after new addrs are set. --- firmware/microblaze/apps/txrx.c | 30 ++++++++++++++-------- firmware/microblaze/lib/ethernet.c | 2 +- firmware/microblaze/lib/net_common.c | 23 ++++++++--------- firmware/microblaze/lib/net_common.h | 13 ++-------- host/apps/usrp2_burner.cpp | 1 + host/apps/usrp2_recovery.py | 50 ++++++++++++++++++++++++++++++++++++ host/lib/device.cpp | 4 +-- host/lib/transport/udp_simple.cpp | 2 +- 8 files changed, 86 insertions(+), 39 deletions(-) create mode 100755 host/apps/usrp2_recovery.py (limited to 'host/lib/transport') diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 8949f1263..b82c7702b 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -148,14 +148,6 @@ static struct socket_address fp_socket_src, fp_socket_dst; void start_rx_streaming_cmd(void); void stop_rx_cmd(void); -static eth_mac_addr_t get_my_eth_mac_addr(void){ - return *ethernet_mac_addr(); -} - -static struct ip_addr get_my_ip_addr(void){ - return *get_ip_addr(); -} - static void print_ip_addr(const void *t){ uint8_t *p = (uint8_t *)t; printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); @@ -166,7 +158,7 @@ void handle_udp_data_packet( unsigned char *payload, int payload_len ){ //its a tiny payload, load the fast-path variables - fp_mac_addr_src = get_my_eth_mac_addr(); + fp_mac_addr_src = *ethernet_mac_addr(); arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); fp_socket_src = dst; fp_socket_dst = src; @@ -540,6 +532,21 @@ eth_pkt_inspector(dbsm_t *sm, int bufno) ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != 0) ) return false; + //test if its an ip recovery packet + typedef struct{ + padded_eth_hdr_t eth_hdr; + char code[4]; + union { + struct ip_addr ip_addr; + } data; + }recovery_packet_t; + recovery_packet_t *recovery_packet = (recovery_packet_t *)buff; + if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){ + printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline(); + set_ip_addr(&recovery_packet->data.ip_addr); + return true; + } + //pass it to the slow-path handler size_t len = buffer_pool_status->last_line[bufno] - 3; handle_eth_packet(buff, len); @@ -737,8 +744,9 @@ main(void) ethernet_register_link_changed_callback(link_changed_callback); ethernet_init(); - register_get_eth_mac_addr(get_my_eth_mac_addr); - register_get_ip_addr(get_my_ip_addr); + register_mac_addr(ethernet_mac_addr()); + register_ip_addr(get_ip_addr()); + register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/lib/ethernet.c index 0e731c68c..34a3ad7c1 100644 --- a/firmware/microblaze/lib/ethernet.c +++ b/firmware/microblaze/lib/ethernet.c @@ -320,7 +320,7 @@ ethernet_set_mac_addr(const eth_mac_addr_t *t) if (ok){ src_mac_addr = *t; src_mac_addr_initialized = true; - eth_mac_set_addr(t); + //eth_mac_set_addr(t); //this breaks the link } return ok; diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c index 693502d18..67a3ff964 100644 --- a/firmware/microblaze/lib/net_common.c +++ b/firmware/microblaze/lib/net_common.c @@ -51,16 +51,14 @@ ip_addr_eq(const struct ip_addr a, const struct ip_addr b) // ------------------------------------------------------------------------ -get_eth_mac_addr_t _get_eth_mac_addr = NULL; - -void register_get_eth_mac_addr(get_eth_mac_addr_t get_eth_mac_addr){ - _get_eth_mac_addr = get_eth_mac_addr; +static eth_mac_addr_t _local_mac_addr; +void register_mac_addr(const eth_mac_addr_t *mac_addr){ + _local_mac_addr = *mac_addr; } -get_ip_addr_t _get_ip_addr = NULL; - -void register_get_ip_addr(get_ip_addr_t get_ip_addr){ - _get_ip_addr = get_ip_addr; +static struct ip_addr _local_ip_addr; +void register_ip_addr(const struct ip_addr *ip_addr){ + _local_ip_addr = *ip_addr; } //------------------------------------------------------------------------- @@ -140,7 +138,7 @@ send_pkt(eth_mac_addr_t dst, int ethertype, padded_eth_hdr_t ehdr; ehdr.pad = 0; ehdr.dst = dst; - ehdr.src = _get_eth_mac_addr(); + ehdr.src = _local_mac_addr; ehdr.ethertype = ethertype; uint32_t *p = buffer_ram(CPU_TX_BUF); @@ -218,7 +216,6 @@ send_ip_pkt(struct ip_addr dst, int protocol, const void *buf0, size_t len0, const void *buf1, size_t len1) { - struct ip_addr src = _get_ip_addr(); int ttl = 32; struct ip_hdr ip; @@ -228,7 +225,7 @@ send_ip_pkt(struct ip_addr dst, int protocol, IPH_OFFSET_SET(&ip, IP_DF); /* don't fragment */ ip._ttl_proto = (ttl << 8) | (protocol & 0xff); ip._chksum = 0; - ip.src = src; + ip.src = _local_ip_addr; ip.dest = dst; ip._chksum = ~chksum_buffer((unsigned short *) &ip, @@ -373,8 +370,8 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) sip.addr = get_int32(p->ar_sip); tip.addr = get_int32(p->ar_tip); - if (ip_addr_eq(tip, _get_ip_addr())){ // They're looking for us... - send_arp_reply(p, _get_eth_mac_addr()); + if (ip_addr_eq(tip, _local_ip_addr)){ // They're looking for us... + send_arp_reply(p, _local_mac_addr); } } diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h index 6cd45bf69..112669b46 100644 --- a/firmware/microblaze/lib/net_common.h +++ b/firmware/microblaze/lib/net_common.h @@ -33,21 +33,12 @@ extern dbsm_t *ac_could_be_sending_to_eth; void stop_streaming(void); -/*! - * Helpful typedefs for callback - */ typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len); -typedef eth_mac_addr_t (*get_eth_mac_addr_t)(void); -typedef struct ip_addr (*get_ip_addr_t)(void); - -/*! - * Functions to register callbacks - */ -void register_get_eth_mac_addr(get_eth_mac_addr_t get_eth_mac_addr); +void register_mac_addr(const eth_mac_addr_t *mac_addr); -void register_get_ip_addr(get_ip_addr_t get_ip_addr); +void register_ip_addr(const struct ip_addr *ip_addr); void register_udp_listener(int port, udp_receiver_t rcvr); diff --git a/host/apps/usrp2_burner.cpp b/host/apps/usrp2_burner.cpp index 08ec8daf9..941e71d0c 100644 --- a/host/apps/usrp2_burner.cpp +++ b/host/apps/usrp2_burner.cpp @@ -79,5 +79,6 @@ int main(int argc, char *argv[]){ std::cout << " Done" << std::endl; } + std::cout << "Power-cycle the usrp2 for the changes to take effect." << std::endl; return 0; } diff --git a/host/apps/usrp2_recovery.py b/host/apps/usrp2_recovery.py new file mode 100755 index 000000000..00d231cdb --- /dev/null +++ b/host/apps/usrp2_recovery.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +""" +The usrp2 recovery app: + +When the usrp2 has an unknown or bad ip address in its eeprom, +it may not be possible to communicate with the usrp2 over ip/udp. + +This app will send a raw ethernet packet to bypass the ip layer. +The packet will contain a known ip address to burn into eeprom. +Because the recovery packet is sent with a broadcast mac address, +only one usrp2 should be present on the interface upon execution. + +This app requires super-user privileges and only works on linux. +""" + +import socket +import struct +import optparse + +BCAST_MAC_ADDR = 'ff:ff:ff:ff:ff:ff' +RECOVERY_ETHERTYPE = 0xbeee +IP_RECOVERY_CODE = 'addr' + +def mac_addr_repr_to_binary_string(mac_addr): + return ''.join(map(lambda x: chr(int(x, 16)), mac_addr.split(':'))) + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.add_option('--ifc', type='string', help='ethernet interface name [default=%default]', default='eth0') + parser.add_option('--new-ip', type='string', help='ip address to set [default=%default]', default='192.168.10.2') + (options, args) = parser.parse_args() + + #create the raw socket + print "Opening raw socket on interface: ", options.ifc + soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) + soc.bind((options.ifc, RECOVERY_ETHERTYPE)) + + #create the recovery packet + print "Loading packet with new ip address: ", options.new_ip + packet = struct.pack( + '!6s6sH4s4s', + mac_addr_repr_to_binary_string(BCAST_MAC_ADDR), + mac_addr_repr_to_binary_string(BCAST_MAC_ADDR), + RECOVERY_ETHERTYPE, + IP_RECOVERY_CODE, + socket.inet_aton(options.new_ip), + ) + soc.send(packet) + print "Done" diff --git a/host/lib/device.cpp b/host/lib/device.cpp index a87ba83eb..897084427 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -109,14 +109,14 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ //check that we found any devices if (dev_addr_makers.size() == 0){ throw std::runtime_error(str( - boost::format("No devices found for %s") % device_addr::to_string(hint) + boost::format("No devices found for ----->\n%s") % device_addr::to_string(hint) )); } //check that the which index is valid if (dev_addr_makers.size() <= which){ throw std::runtime_error(str( - boost::format("No device at index %d for %s") % which % device_addr::to_string(hint) + boost::format("No device at index %d for ----->\n%s") % which % device_addr::to_string(hint) )); } diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 7004bdfdf..3c8ecb70d 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -38,7 +38,7 @@ static void reasonable_recv_timeout( boost::asio::ip::udp::socket &socket ){ boost::asio::deadline_timer timer(socket.get_io_service()); - timer.expires_from_now(boost::posix_time::milliseconds(50)); + timer.expires_from_now(boost::posix_time::milliseconds(100)); while (not (socket.available() or timer.expires_from_now().is_negative())){ boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } -- cgit v1.2.3 From 69aaffa6d8d4614dbf6b751fe058e39fced68153 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 17 Mar 2010 17:55:20 -0800 Subject: got uhd almost compiling in windowze. figured out special flags. also had to use boost stdint because its missing in visual c++, added a bunch of numeric casts to reduce warnings --- host/CMakeLists.txt | 19 ++++-- host/include/uhd/device_addr.hpp | 5 +- host/include/uhd/metadata.hpp | 8 +-- host/include/uhd/time_spec.hpp | 8 +-- host/include/uhd/transport/vrt.hpp | 14 ++-- host/include/uhd/usrp/dboard_id.hpp | 4 +- host/include/uhd/usrp/dboard_interface.hpp | 12 ++-- host/lib/CMakeLists.txt | 5 +- host/lib/device.cpp | 2 +- host/lib/device_addr.cpp | 6 +- host/lib/time_spec.cpp | 8 +-- host/lib/transport/udp_zero_copy_none.cpp | 10 +-- host/lib/transport/vrt.cpp | 21 +++--- host/lib/usrp/usrp2/dboard_impl.cpp | 4 +- host/lib/usrp/usrp2/dboard_interface.cpp | 28 ++++---- host/lib/usrp/usrp2/dsp_impl.cpp | 23 ++++--- host/lib/usrp/usrp2/fw_common.h | 100 +++++++++++++++-------------- host/lib/usrp/usrp2/io_impl.cpp | 65 ++++++++++--------- host/lib/usrp/usrp2/usrp2_impl.hpp | 10 +-- host/test/vrt_test.cpp | 2 +- host/test/wax_test.cpp | 2 +- 21 files changed, 191 insertions(+), 165 deletions(-) (limited to 'host/lib/transport') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 30f4789a3..3576a690f 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -53,10 +53,18 @@ FUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have) ENDIF(${have}) ENDFUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG) -UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL) -UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA) -UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC) -UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) +IF(UNIX) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) +ENDIF(UNIX) + +IF(WIN32) + ADD_DEFINITIONS(-Dnot=! -Dand=&& -Dor=||) #logical operators + ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #as requested by vs + ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max +ENDIF(WIN32) ######################################################################## # Setup Boost @@ -64,6 +72,7 @@ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) FIND_PACKAGE(Boost 1.36 REQUIRED date_time program_options + regex system thread unit_test_framework @@ -78,7 +87,7 @@ LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) INCLUDE(TestBigEndian) TEST_BIG_ENDIAN(HAVE_BIG_ENDIAN) IF(HAVE_BIG_ENDIAN) - ADD_DEFINITIONS("-DHAVE_BIG_ENDIAN=/* */") + ADD_DEFINITIONS(-DHAVE_BIG_ENDIAN) ENDIF(HAVE_BIG_ENDIAN) ######################################################################## diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp index ed538453a..1b624b770 100644 --- a/host/include/uhd/device_addr.hpp +++ b/host/include/uhd/device_addr.hpp @@ -19,10 +19,9 @@ #define INCLUDED_UHD_DEVICE_ADDR_HPP #include +#include #include #include -#include -#include #include namespace uhd{ @@ -32,7 +31,7 @@ namespace uhd{ * Provides conversion between string and binary formats. */ struct mac_addr_t{ - struct ether_addr mac_addr; + boost::uint8_t mac_addr[6]; mac_addr_t(const std::string &mac_addr_str = "00:00:00:00:00:00"); std::string to_string(void) const; }; diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp index 0588ef0ed..ce72ff14b 100644 --- a/host/include/uhd/metadata.hpp +++ b/host/include/uhd/metadata.hpp @@ -28,9 +28,9 @@ namespace uhd{ * The receive routines will convert IF data headers into metadata. */ struct rx_metadata_t{ - uint32_t stream_id; - bool has_stream_id; + boost::uint32_t stream_id; time_spec_t time_spec; + bool has_stream_id; bool has_time_spec; bool is_fragment; @@ -44,9 +44,9 @@ struct rx_metadata_t{ * The send routines will convert the metadata to IF data headers. */ struct tx_metadata_t{ - uint32_t stream_id; - bool has_stream_id; + boost::uint32_t stream_id; time_spec_t time_spec; + bool has_stream_id; bool has_time_spec; bool start_of_burst; bool end_of_burst; diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp index 7e182236b..588758824 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/time_spec.hpp @@ -16,7 +16,7 @@ // #include -#include +#include #ifndef INCLUDED_UHD_TIME_SPEC_HPP #define INCLUDED_UHD_TIME_SPEC_HPP @@ -30,8 +30,8 @@ namespace uhd{ * and for controlling the start of streaming for applicable dsps. */ struct time_spec_t{ - uint32_t secs; - uint32_t ticks; + boost::uint32_t secs; + boost::uint32_t ticks; /*! * Create a time_spec_t that holds a wildcard time. @@ -44,7 +44,7 @@ namespace uhd{ * \param new_secs the new seconds * \param new_ticks the new ticks (default = 0) */ - time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0); + time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks = 0); /*! * Create a time_spec_t from boost posix time. diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index 1700d2785..3b5bf41bf 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -38,7 +38,7 @@ namespace vrt{ */ void pack( const tx_metadata_t &metadata, //input - uint32_t *header_buff, //output + boost::uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input size_t &num_packet_words32, //output @@ -55,12 +55,12 @@ namespace vrt{ * \param packet_count the packet count sequence number */ void unpack( - rx_metadata_t &metadata, //output - const uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count //output + rx_metadata_t &metadata, //output + const boost::uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t num_packet_words32, //input + size_t &packet_count //output ); } //namespace vrt diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 34406863d..62c61661c 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -15,15 +15,15 @@ // along with this program. If not, see . // +#include #include -#include #ifndef INCLUDED_UHD_USRP_DBOARD_ID_HPP #define INCLUDED_UHD_USRP_DBOARD_ID_HPP namespace uhd{ namespace usrp{ -typedef uint16_t dboard_id_t; +typedef boost::uint16_t dboard_id_t; static const dboard_id_t ID_NONE = 0xffff; diff --git a/host/include/uhd/usrp/dboard_interface.hpp b/host/include/uhd/usrp/dboard_interface.hpp index 84e1f5b22..b00643550 100644 --- a/host/include/uhd/usrp/dboard_interface.hpp +++ b/host/include/uhd/usrp/dboard_interface.hpp @@ -19,8 +19,8 @@ #define INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP #include +#include #include -#include namespace uhd{ namespace usrp{ @@ -33,7 +33,7 @@ namespace uhd{ namespace usrp{ class dboard_interface{ public: typedef boost::shared_ptr sptr; - typedef std::vector byte_vector_t; + typedef std::vector byte_vector_t; //tells the host which unit to use enum unit_type_t{ @@ -96,7 +96,7 @@ public: * \param rx_value 16-bits, 0=FPGA output low, 1=FPGA output high * \param mask 16-bits, 0=software, 1=atr */ - virtual void set_atr_reg(gpio_bank_t bank, uint16_t tx_value, uint16_t rx_value, uint16_t mask) = 0; + virtual void set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask) = 0; /*! * Set daughterboard GPIO data direction register. @@ -105,7 +105,7 @@ public: * \param value 16-bits, 0=FPGA input, 1=FPGA output * \param mask 16-bits, 0=ignore, 1=set */ - virtual void set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint16_t mask) = 0; + virtual void set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask) = 0; /*! * Set daughterboard GPIO pin values. @@ -114,7 +114,7 @@ public: * \param value 16 bits, 0=low, 1=high * \param mask 16 bits, 0=ignore, 1=set */ - virtual void write_gpio(gpio_bank_t bank, uint16_t value, uint16_t mask) = 0; + virtual void write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask) = 0; /*! * Read daughterboard GPIO pin values @@ -122,7 +122,7 @@ public: * \param bank GPIO_TX_BANK or GPIO_RX_BANK * \return the value of the gpio bank */ - virtual uint16_t read_gpio(gpio_bank_t bank) = 0; + virtual boost::uint16_t read_gpio(gpio_bank_t bank) = 0; /*! * \brief Write to I2C peripheral diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 1d2c5471b..46e1b0947 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -61,4 +61,7 @@ ADD_LIBRARY(uhd SHARED ${libuhd_sources}) TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES}) -INSTALL(TARGETS uhd LIBRARY DESTINATION ${LIBRARY_DIR}) +INSTALL(TARGETS uhd + LIBRARY DESTINATION ${LIBRARY_DIR} + ARCHIVE DESTINATION ${LIBRARY_DIR} +) diff --git a/host/lib/device.cpp b/host/lib/device.cpp index 897084427..cd8a01ab4 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -136,7 +136,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ return hash_to_device[dev_hash].lock(); } //create and register a new device - catch(const std::assert_error &e){ + catch(const std::assert_error &){ device::sptr dev = maker(dev_addr); hash_to_device[dev_hash] = dev; return dev; diff --git a/host/lib/device_addr.cpp b/host/lib/device_addr.cpp index 9514df981..d26bb4b9d 100644 --- a/host/lib/device_addr.cpp +++ b/host/lib/device_addr.cpp @@ -28,7 +28,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){ std::string mac_addr_str = (mac_addr_str_ == "")? "ff:ff:ff:ff:ff:ff" : mac_addr_str_; //ether_aton_r(str.c_str(), &mac_addr); - uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB + boost::uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB try{ //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx @@ -43,7 +43,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){ int hex_num; std::istringstream iss(hex_strs[i]); iss >> std::hex >> hex_num; - p[i] = uint8_t(hex_num); + p[i] = boost::uint8_t(hex_num); } } @@ -58,7 +58,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){ std::string uhd::mac_addr_t::to_string(void) const{ //ether_ntoa_r(&mac_addr, addr_buf); - const uint8_t *p = reinterpret_cast(&mac_addr); + const boost::uint8_t *p = reinterpret_cast(&mac_addr); return str( boost::format("%02x:%02x:%02x:%02x:%02x:%02x") % int(p[0]) % int(p[1]) % int(p[2]) diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp index 193441342..210010394 100644 --- a/host/lib/time_spec.cpp +++ b/host/lib/time_spec.cpp @@ -24,17 +24,17 @@ time_spec_t::time_spec_t(void){ ticks = ~0; } -time_spec_t::time_spec_t(uint32_t new_secs, uint32_t new_ticks){ +time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){ secs = new_secs; ticks = new_ticks; } static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); -static double time_tick_rate(boost::posix_time::time_duration::ticks_per_second()); +static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second()); time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ boost::posix_time::time_duration td = time - epoch; - secs = td.total_seconds(); + secs = boost::uint32_t(td.total_seconds()); double time_ticks_per_device_ticks = time_tick_rate/tick_rate; - ticks = td.fractional_seconds()/time_ticks_per_device_ticks; + ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); } diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp index e29530cf1..219ae8720 100644 --- a/host/lib/transport/udp_zero_copy_none.cpp +++ b/host/lib/transport/udp_zero_copy_none.cpp @@ -16,8 +16,10 @@ // #include +#include #include #include +#include using namespace uhd::transport; @@ -36,7 +38,7 @@ public: } ~smart_buffer_impl(void){ - delete [] boost::asio::buffer_cast(_buff); + delete [] boost::asio::buffer_cast(_buff); } const boost::asio::const_buffer &get(void) const{ @@ -89,12 +91,12 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin // set the rx socket buffer size: // pick a huge size, and deal with whatever we get - set_recv_buff_size(54321e3); //some big number! + set_recv_buff_size(size_t(54321e3)); //some big number! size_t current_buff_size = get_recv_buff_size(); std::cout << boost::format( "Current rx socket buffer size: %d\n" ) % current_buff_size; - if (current_buff_size < .1e6) std::cout << boost::format( + if (current_buff_size < size_t(.1e6)) std::cout << boost::format( "Adjust max rx socket buffer size (linux only):\n" " sysctl -w net.core.rmem_max=VALUE\n" ); @@ -119,7 +121,7 @@ smart_buffer::sptr udp_zero_copy_impl::recv(void){ } //allocate memory and create buffer - uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)]; + boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; boost::asio::mutable_buffer buff(buff_mem, available); //receive only if data is available diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 5029df217..a06b5bf21 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -16,20 +16,21 @@ // #include -#include +#include //endianness conversion #include +using namespace uhd; using namespace uhd::transport; void vrt::pack( const tx_metadata_t &metadata, //input - uint32_t *header_buff, //output + boost::uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input size_t &num_packet_words32, //output size_t packet_count //input ){ - uint32_t vrt_hdr_flags = 0; + boost::uint32_t vrt_hdr_flags = 0; num_header_words32 = 1; //load the vrt header and flags @@ -58,18 +59,18 @@ void vrt::pack( } void vrt::unpack( - rx_metadata_t &metadata, //output - const uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count //output + rx_metadata_t &metadata, //output + const boost::uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t num_packet_words32, //input + size_t &packet_count //output ){ //clear the metadata metadata = rx_metadata_t(); //extract vrt header - uint32_t vrt_hdr_word = ntohl(header_buff[0]); + boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]); size_t packet_words32 = vrt_hdr_word & 0xffff; packet_count = (vrt_hdr_word >> 16) & 0xf; diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 502a7daa0..60622ca47 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -62,7 +62,7 @@ void usrp2_impl::dboard_init(void){ void usrp2_impl::update_mux_config(void){ //calculate the rx mux - uint32_t rx_mux = 0; + boost::uint32_t rx_mux = 0; ASSERT_THROW(_rx_subdevs_in_use.size() == 1); wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0)); std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as() << std::endl; @@ -76,7 +76,7 @@ void usrp2_impl::update_mux_config(void){ } //calculate the tx mux - uint32_t tx_mux = 0x10; + boost::uint32_t tx_mux = 0x10; ASSERT_THROW(_tx_subdevs_in_use.size() == 1); wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0)); std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as() << std::endl; diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index cefd69ba9..d20465147 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -28,10 +28,10 @@ public: void write_aux_dac(unit_type_t, int, int); int read_aux_adc(unit_type_t, int); - void set_atr_reg(gpio_bank_t, uint16_t, uint16_t, uint16_t); - void set_gpio_ddr(gpio_bank_t, uint16_t, uint16_t); - void write_gpio(gpio_bank_t, uint16_t, uint16_t); - uint16_t read_gpio(gpio_bank_t); + void set_atr_reg(gpio_bank_t, boost::uint16_t, boost::uint16_t, boost::uint16_t); + void set_gpio_ddr(gpio_bank_t, boost::uint16_t, boost::uint16_t); + void write_gpio(gpio_bank_t, boost::uint16_t, boost::uint16_t); + boost::uint16_t read_gpio(gpio_bank_t); void write_i2c(int, const byte_vector_t &); byte_vector_t read_i2c(int, size_t); @@ -89,7 +89,7 @@ double usrp2_dboard_interface::get_tx_clock_rate(void){ * \param bank the dboard interface gpio bank enum * \return an over the wire representation */ -static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ +static boost::uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ switch(bank){ case uhd::usrp::dboard_interface::GPIO_TX_BANK: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::GPIO_RX_BANK: return USRP2_DIR_RX; @@ -97,7 +97,7 @@ static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ throw std::invalid_argument("unknown gpio bank type"); } -void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint16_t mask){ +void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_GPIO_DDR_SETTINGS_BRO); @@ -110,7 +110,7 @@ void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_GPIO_DDR_SETTINGS_DUDE); } -void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16_t mask){ +void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_SET_YOUR_GPIO_PIN_OUTS_BRO); @@ -123,7 +123,7 @@ void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16 ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_I_SET_THE_GPIO_PIN_OUTS_DUDE); } -uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ +boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_GPIO_PIN_VALS_BRO); @@ -135,7 +135,7 @@ uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ return ntohs(in_data.data.gpio_config.value); } -void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, uint16_t rx_value, uint16_t mask){ +void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_ATR_SETTINGS_BRO); @@ -158,7 +158,7 @@ void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, ui * \param dev the dboard interface spi dev enum * \return an over the wire representation */ -static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ +static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ switch(dev){ case uhd::usrp::dboard_interface::SPI_TX_DEV: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::SPI_RX_DEV: return USRP2_DIR_RX; @@ -172,7 +172,7 @@ static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ * \param latch the dboard interface spi latch enum * \return an over the wire representation */ -static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ +static boost::uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ switch(latch){ case uhd::usrp::dboard_interface::SPI_LATCH_RISE: return USRP2_CLK_EDGE_RISE; case uhd::usrp::dboard_interface::SPI_LATCH_FALL: return USRP2_CLK_EDGE_FALL; @@ -186,7 +186,7 @@ static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ * \param push the dboard interface spi push enum * \return an over the wire representation */ -static uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){ +static boost::uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){ switch(push){ case uhd::usrp::dboard_interface::SPI_PUSH_RISE: return USRP2_CLK_EDGE_RISE; case uhd::usrp::dboard_interface::SPI_PUSH_FALL: return USRP2_CLK_EDGE_FALL; @@ -286,7 +286,7 @@ dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, s * \param unit the dboard interface unit type enum * \return an over the wire representation */ -static uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ +static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ switch(unit){ case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; @@ -300,7 +300,7 @@ void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, i out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); out_data.data.aux_args.dir = spi_dev_to_otw(unit); out_data.data.aux_args.which = which; - out_data.data.aux_args.dir = htonl(value); + out_data.data.aux_args.value = htonl(value); //send and recv usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7520c1757..54ed45e41 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "usrp2_impl.hpp" using namespace uhd; @@ -25,14 +26,20 @@ using namespace uhd; static const size_t default_decim = 16; static const size_t default_interp = 16; +#define rint boost::math::iround + +template T log2(T num){ + return std::log(num)/std::log(T(2)); +} + /*********************************************************************** * DDC Helper Methods **********************************************************************/ -static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ - double scale_factor = pow(2.0, 32); +static boost::uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ + double scale_factor = std::pow(2.0, 32); //calculate the freq register word - uint32_t freq_word = rint((freq / clock_freq) * scale_factor); + boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor); //update the actual frequency freq = (double(freq_word) / scale_factor) * clock_freq; @@ -40,8 +47,8 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t return freq_word; } -static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){ - return (uint16_t(i) << 16) | (uint16_t(q) << 0); +static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){ + return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0); } void usrp2_impl::init_ddc_config(void){ @@ -69,7 +76,7 @@ void usrp2_impl::update_ddc_config(void){ calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq()) ); out_data.data.ddc_args.decim = htonl(_ddc_decim); - static const uint32_t default_rx_scale_iq = 1024; + static const boost::int16_t default_rx_scale_iq = 1024; out_data.data.ddc_args.scale_iq = htonl( calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) ); @@ -211,8 +218,8 @@ void usrp2_impl::update_duc_config(void){ while(tmp_interp > 128) tmp_interp /= 2; // Calculate closest multiplier constant to reverse gain absent scale multipliers - size_t interp_cubed = pow(tmp_interp, 3); - size_t scale = rint((4096*pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed)); + double interp_cubed = std::pow(double(tmp_interp), 3); + boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed)); //setup the out data usrp2_ctrl_data_t out_data; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 03e8d3a37..9740448ee 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -24,7 +24,11 @@ * Therefore, this header may only contain valid C code. */ #ifdef __cplusplus +#include +#define _SINS_ boost:://stdint namespace when in c++ extern "C" { +#else +#include #endif // size of the vrt header and trailer to the host @@ -128,78 +132,78 @@ typedef enum{ } usrp2_clk_edge_t; typedef struct{ - uint32_t id; - uint32_t seq; + _SINS_ uint32_t id; + _SINS_ uint32_t seq; union{ - uint32_t ip_addr; - uint8_t mac_addr[6]; + _SINS_ uint32_t ip_addr; + _SINS_ uint8_t mac_addr[6]; struct { - uint16_t rx_id; - uint16_t tx_id; + _SINS_ uint16_t rx_id; + _SINS_ uint16_t tx_id; } dboard_ids; struct { - uint8_t pps_source; - uint8_t pps_polarity; - uint8_t ref_source; - uint8_t _pad; + _SINS_ uint8_t pps_source; + _SINS_ uint8_t pps_polarity; + _SINS_ uint8_t ref_source; + _SINS_ uint8_t _pad; } clock_config; struct { - uint8_t bank; - uint8_t _pad[3]; - uint16_t value; - uint16_t mask; + _SINS_ uint8_t bank; + _SINS_ uint8_t _pad[3]; + _SINS_ uint16_t value; + _SINS_ uint16_t mask; } gpio_config; struct { - uint8_t bank; - uint8_t _pad[3]; - uint16_t tx_value; - uint16_t rx_value; - uint16_t mask; + _SINS_ uint8_t bank; + _SINS_ uint8_t _pad[3]; + _SINS_ uint16_t tx_value; + _SINS_ uint16_t rx_value; + _SINS_ uint16_t mask; } atr_config; struct { - uint8_t dev; - uint8_t latch; - uint8_t push; - uint8_t readback; - uint8_t bytes; - uint8_t data[sizeof(uint32_t)]; + _SINS_ uint8_t dev; + _SINS_ uint8_t latch; + _SINS_ uint8_t push; + _SINS_ uint8_t readback; + _SINS_ uint8_t bytes; + _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; } spi_args; struct { - uint8_t addr; - uint8_t bytes; - uint8_t data[sizeof(uint32_t)]; + _SINS_ uint8_t addr; + _SINS_ uint8_t bytes; + _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; } i2c_args; struct { - uint8_t dir; - uint8_t which; - uint8_t _pad[2]; - uint32_t value; + _SINS_ uint8_t dir; + _SINS_ uint8_t which; + _SINS_ uint8_t _pad[2]; + _SINS_ uint32_t value; } aux_args; struct { - uint32_t freq_word; - uint32_t decim; - uint32_t scale_iq; + _SINS_ uint32_t freq_word; + _SINS_ uint32_t decim; + _SINS_ uint32_t scale_iq; } ddc_args; struct { - uint8_t enabled; - uint8_t _pad[3]; - uint32_t secs; - uint32_t ticks; - uint32_t samples; + _SINS_ uint8_t enabled; + _SINS_ uint8_t _pad[3]; + _SINS_ uint32_t secs; + _SINS_ uint32_t ticks; + _SINS_ uint32_t samples; } streaming; struct { - uint32_t freq_word; - uint32_t interp; - uint32_t scale_iq; + _SINS_ uint32_t freq_word; + _SINS_ uint32_t interp; + _SINS_ uint32_t scale_iq; } duc_args; struct { - uint32_t secs; - uint32_t ticks; - uint8_t now; + _SINS_ uint32_t secs; + _SINS_ uint32_t ticks; + _SINS_ uint8_t now; } time_args; struct { - uint32_t rx_mux; - uint32_t tx_mux; + _SINS_ uint32_t rx_mux; + _SINS_ uint32_t tx_mux; } mux_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index e52c1e576..dc8eea243 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include #include "usrp2_impl.hpp" @@ -27,11 +28,11 @@ namespace asio = boost::asio; /*********************************************************************** * Constants **********************************************************************/ -typedef std::complex fc32_t; -typedef std::complex sc16_t; +typedef std::complex fc32_t; +typedef std::complex sc16_t; -static const float shorts_per_float = pow(2.0, 15); -static const float floats_per_short = 1.0/shorts_per_float; +static const float shorts_per_float = float(1 << 15); +static const float floats_per_short = float(1.0/shorts_per_float); /*********************************************************************** * Helper Functions @@ -41,7 +42,7 @@ void usrp2_impl::io_init(void){ _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port - uint32_t zero_data = 0; + boost::uint32_t zero_data = 0; _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); } @@ -66,37 +67,37 @@ static const bool is_big_endian = false; #endif static inline void host_floats_to_usrp2_items( - uint32_t *usrp2_items, + boost::uint32_t *usrp2_items, const fc32_t *host_floats, size_t num_samps ){ unrolled_loop(i, num_samps,{ - uint16_t real = host_floats[i].real()*shorts_per_float; - uint16_t imag = host_floats[i].imag()*shorts_per_float; + boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); + boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); usrp2_items[i] = htonl((real << 16) | (imag << 0)); }); } static inline void usrp2_items_to_host_floats( fc32_t *host_floats, - const uint32_t *usrp2_items, + const boost::uint32_t *usrp2_items, size_t num_samps ){ unrolled_loop(i, num_samps,{ - uint32_t item = ntohl(usrp2_items[i]); - int16_t real = item >> 16; - int16_t imag = item >> 0; - host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short); + boost::uint32_t item = ntohl(usrp2_items[i]); + boost::int16_t real = boost::uint16_t(item >> 16); + boost::int16_t imag = boost::uint16_t(item >> 0); + host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); }); } static inline void host_items_to_usrp2_items( - uint32_t *usrp2_items, - const uint32_t *host_items, + boost::uint32_t *usrp2_items, + const boost::uint32_t *host_items, size_t num_samps ){ if (is_big_endian){ - std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t)); + std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); } else{ unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); @@ -104,12 +105,12 @@ static inline void host_items_to_usrp2_items( } static inline void usrp2_items_to_host_items( - uint32_t *host_items, - const uint32_t *usrp2_items, + boost::uint32_t *host_items, + const boost::uint32_t *usrp2_items, size_t num_samps ){ if (is_big_endian){ - std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t)); + std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); } else{ unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); @@ -124,12 +125,12 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ _rx_smart_buff = _data_transport->recv(); //unpack the vrt header - size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t); + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/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 uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); + const boost::uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); size_t num_header_words32_out, num_payload_words32_out, packet_count_out; try{ vrt::unpack( @@ -156,7 +157,7 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ //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(uint32_t) + num_payload_words32_out*sizeof(boost::uint32_t) ); } @@ -168,8 +169,8 @@ size_t usrp2_impl::send( const tx_metadata_t &metadata, const std::string &type ){ - uint32_t tx_mem[_mtu/sizeof(uint32_t)]; - uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data + boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; + boost::uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data size_t num_samps = _max_tx_samples_per_packet; //calculate the number of samples to be copied @@ -180,13 +181,13 @@ size_t usrp2_impl::send( } else if (type == "16sc"){ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); - host_items_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); + host_items_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); } else{ throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - uint32_t vrt_hdr[vrt::max_header_words32]; + boost::uint32_t vrt_hdr[vrt::max_header_words32]; size_t num_header_words32, num_packet_words32; size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; @@ -202,10 +203,10 @@ size_t usrp2_impl::send( //copy in the vrt header (yes we left space) items -= num_header_words32; - std::memcpy(items, vrt_hdr, num_header_words32*sizeof(uint32_t)); + std::memcpy(items, vrt_hdr, num_header_words32*sizeof(boost::uint32_t)); //send and return number of samples - _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(uint32_t))); + _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(boost::uint32_t))); return num_samps; } @@ -231,8 +232,8 @@ size_t usrp2_impl::recv( //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 = bytes_to_copy/sizeof(uint32_t); - const uint32_t *items = asio::buffer_cast(_rx_copy_buff); + size_t num_samps = bytes_to_copy/sizeof(boost::uint32_t); + const boost::uint32_t *items = asio::buffer_cast(_rx_copy_buff); //calculate the number of samples to be copied //and copy the samples from the recv buffer @@ -242,7 +243,7 @@ size_t usrp2_impl::recv( } else if (type == "16sc"){ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); - usrp2_items_to_host_items(asio::buffer_cast(buff), items, num_samps); + usrp2_items_to_host_items(asio::buffer_cast(buff), items, num_samps); } else{ throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); @@ -250,7 +251,7 @@ size_t usrp2_impl::recv( //update the rx copy buffer to reflect the bytes copied _rx_copy_buff = asio::buffer( - items + num_samps, bytes_to_copy - num_samps*sizeof(uint32_t) + items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t) ); return num_samps; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2c6b6f8c9..765c523fe 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -115,17 +115,17 @@ public: private: //the raw io interface (samples are in the usrp2 native format) void recv_raw(uhd::rx_metadata_t &); - uhd::dict _tx_stream_id_to_packet_seq; - uhd::dict _rx_stream_id_to_packet_seq; + uhd::dict _tx_stream_id_to_packet_seq; + uhd::dict _rx_stream_id_to_packet_seq; 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(uint32_t) - + (_mtu - _hdrs)/sizeof(boost::uint32_t) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - USRP2_HOST_RX_VRT_TRAILER_WORDS32 ; static const size_t _max_tx_samples_per_packet = - (_mtu - _hdrs)/sizeof(uint32_t) - + (_mtu - _hdrs)/sizeof(boost::uint32_t) - uhd::transport::vrt::max_header_words32 ; uhd::transport::smart_buffer::sptr _rx_smart_buff; @@ -137,7 +137,7 @@ private: uhd::transport::udp_zero_copy::sptr _data_transport; //private vars for dealing with send/recv control - uint32_t _ctrl_seq_num; + boost::uint32_t _ctrl_seq_num; boost::mutex _ctrl_mutex; //methods and shadows for clock configuration diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index d80908c74..40116e110 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -25,7 +25,7 @@ static void pack_and_unpack( size_t num_payload_words32, size_t packet_count ){ - uint32_t header_buff[vrt::max_header_words32]; + boost::uint32_t header_buff[vrt::max_header_words32]; size_t num_header_words32; size_t num_packet_words32; diff --git a/host/test/wax_test.cpp b/host/test/wax_test.cpp index b793b2690..cb3b12052 100644 --- a/host/test/wax_test.cpp +++ b/host/test/wax_test.cpp @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(test_set_get){ for (size_t i = 0; i < 10; i++){ for (size_t j = 0; j < 10; j++){ for (size_t k = 0; k < 10; k++){ - float val = i * j * k + i + j + k; + float val = float(i * j * k + i + j + k); //std::cout << i << " " << j << " " << k << std::endl; wd[i][j][k] = val; BOOST_CHECK_EQUAL(val, wd[i][j][k].as()); -- cgit v1.2.3 From d1ecc555e53770f1a5608000352f56f48c36c310 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 21 Mar 2010 00:58:34 -0700 Subject: Moved typedefs from props.hpp into new file types.hpp. Created structs to replace range tuples, and clock config struct. Merged clock config props into one property using config struct. Added templated dict construction to use the assign::map_list_of. Added gcc flag to set visibility to hidden and use the api macro. --- host/CMakeLists.txt | 4 +- host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/dict.hpp | 13 +++ host/include/uhd/props.hpp | 33 ++----- host/include/uhd/simple_device.hpp | 26 +---- host/include/uhd/types.hpp | 83 ++++++++++++++++ host/include/uhd/utils.hpp | 5 +- host/lib/CMakeLists.txt | 3 +- host/lib/gain_handler.cpp | 28 +++--- host/lib/simple_device.cpp | 33 ++----- host/lib/transport/udp_zero_copy_asio.cpp | 154 ++++++++++++++++++++++++++++++ host/lib/transport/udp_zero_copy_none.cpp | 154 ------------------------------ host/lib/types.cpp | 57 +++++++++++ host/lib/usrp/dboard/basic.cpp | 1 + host/lib/usrp/usrp2/mboard_impl.cpp | 74 ++++++-------- host/lib/usrp/usrp2/usrp2_impl.hpp | 11 ++- host/test/gain_handler_test.cpp | 11 +-- 17 files changed, 388 insertions(+), 303 deletions(-) create mode 100644 host/include/uhd/types.hpp create mode 100644 host/lib/transport/udp_zero_copy_asio.cpp delete mode 100644 host/lib/transport/udp_zero_copy_none.cpp create mode 100644 host/lib/types.cpp (limited to 'host/lib/transport') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 29d721464..2f5d03f7d 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -58,11 +58,13 @@ IF(UNIX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC) 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) ENDIF(UNIX) IF(WIN32) ADD_DEFINITIONS(-Dnot=! -Dand=&& -Dor=||) #logical operators - ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #as requested by vs + ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 17c260c24..3d00462cf 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -29,6 +29,7 @@ INSTALL(FILES props.hpp simple_device.hpp time_spec.hpp + types.hpp utils.hpp wax.hpp DESTINATION ${HEADER_DIR}/uhd diff --git a/host/include/uhd/dict.hpp b/host/include/uhd/dict.hpp index 8f7cd5a0f..f08493952 100644 --- a/host/include/uhd/dict.hpp +++ b/host/include/uhd/dict.hpp @@ -39,6 +39,19 @@ namespace uhd{ /* NOP */ } + /*! + * Input iterator constructor: + * Makes boost::assign::map_list_of work. + * \param first the begin iterator + * \param last the end iterator + */ + template + dict(InputIterator first, InputIterator last){ + for(InputIterator it = first; it != last; it++){ + _map.push_back(*it); + } + } + /*! * Destroy this dict. */ diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index 7229d4a12..41e0eff63 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -18,34 +18,14 @@ #ifndef INCLUDED_UHD_PROPS_HPP #define INCLUDED_UHD_PROPS_HPP -#include -#include +#include #include -#include +#include #include +#include namespace uhd{ - //common typedefs for board properties - typedef float gain_t; - typedef double freq_t; - - //gain range tuple (min, max, step) - typedef boost::tuple gain_range_t; - - //freq range tuple (min, max) - typedef boost::tuple freq_range_t; - - //scalar types (have not used yet, dont uncomment until needed) - //typedef int int_scalar_t; - //typedef float real_scalar_t; - //typedef std::complex complex_scalar_t; - - //vector types (have not used yet, dont uncomment until needed) - //typedef std::vector int_vec_t; - //typedef std::vector real_vec_t; - //typedef std::vector complex_vec_t; - //typedef for handling named properties typedef std::vector prop_names_t; typedef boost::tuple named_prop_t; @@ -55,7 +35,8 @@ namespace uhd{ * \param key a reference to the prop object * \param name a reference to the name object */ - inline named_prop_t extract_named_prop(const wax::obj &key, const std::string &name = ""){ + inline UHD_API named_prop_t //must be exported as part of the api to work (TODO move guts to cpp file) + extract_named_prop(const wax::obj &key, const std::string &name = ""){ if (key.type() == typeid(named_prop_t)){ return key.as(); } @@ -94,10 +75,8 @@ namespace uhd{ MBOARD_PROP_RX_DBOARD_NAMES, //ro, prop_names_t MBOARD_PROP_TX_DBOARD, //ro, wax::obj MBOARD_PROP_TX_DBOARD_NAMES, //ro, prop_names_t - MBOARD_PROP_PPS_SOURCE, //rw, std::string (sma, mimo) + MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t MBOARD_PROP_PPS_SOURCE_NAMES, //ro, prop_names_t - MBOARD_PROP_PPS_POLARITY, //rw, std::string (pos, neg) - MBOARD_PROP_REF_SOURCE, //rw, std::string (int, sma, mimo) MBOARD_PROP_REF_SOURCE_NAMES, //ro, prop_names_t MBOARD_PROP_TIME_NOW, //wo, time_spec_t MBOARD_PROP_TIME_NEXT_PPS //wo, time_spec_t diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp index b5d0fe311..ad25eccdc 100644 --- a/host/include/uhd/simple_device.hpp +++ b/host/include/uhd/simple_device.hpp @@ -20,29 +20,13 @@ #include #include +#include #include #include #include namespace uhd{ -/*! - * The tune result struct holds result of a 2-phase tuning: - * The struct hold the result of tuning the dboard as - * the target and actual intermediate frequency. - * The struct hold the result of tuning the DDC/DUC as - * the target and actual digital converter frequency. - * It also tell us weather or not the spectrum is inverted. - */ -struct UHD_API tune_result_t{ - double target_inter_freq; - double actual_inter_freq; - double target_dxc_freq; - double actual_dxc_freq; - bool spectrum_inverted; - tune_result_t(void); -}; - /*! * The simple UHD device class: * A simple device facilitates ease-of-use for most use-case scenarios. @@ -72,11 +56,11 @@ public: virtual std::vector get_rx_rates(void) = 0; virtual tune_result_t set_rx_freq(double freq) = 0; - virtual std::vector get_rx_freq_range(void) = 0; + virtual freq_range_t get_rx_freq_range(void) = 0; virtual void set_rx_gain(float gain) = 0; virtual float get_rx_gain(void) = 0; - virtual std::vector get_rx_gain_range(void) = 0; + virtual gain_range_t get_rx_gain_range(void) = 0; virtual void set_rx_antenna(const std::string &ant) = 0; virtual std::string get_rx_antenna(void) = 0; @@ -90,11 +74,11 @@ public: virtual std::vector get_tx_rates(void) = 0; virtual tune_result_t set_tx_freq(double freq) = 0; - virtual std::vector get_tx_freq_range(void) = 0; + virtual freq_range_t get_tx_freq_range(void) = 0; virtual void set_tx_gain(float gain) = 0; virtual float get_tx_gain(void) = 0; - virtual std::vector get_tx_gain_range(void) = 0; + virtual gain_range_t get_tx_gain_range(void) = 0; virtual void set_tx_antenna(const std::string &ant) = 0; virtual std::string get_tx_antenna(void) = 0; diff --git a/host/include/uhd/types.hpp b/host/include/uhd/types.hpp new file mode 100644 index 000000000..1439f57a1 --- /dev/null +++ b/host/include/uhd/types.hpp @@ -0,0 +1,83 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TYPES_HPP +#define INCLUDED_UHD_TYPES_HPP + +#include +#include + +namespace uhd{ + + typedef float gain_t; //TODO REMOVE + typedef double freq_t; //TODO REMOVE + + /*! + * The gain range struct describes possible gain settings. + * The mimumum gain, maximum gain, and step size are in dB. + */ + struct UHD_API gain_range_t{ + float min, max, step; + gain_range_t(float min = 0.0, float max = 0.0, float step = 0.0); + }; + + /*! + * The frequency range struct describes possible frequency settings. + * Because tuning is very granular (sub-Hz), step size is not listed. + * The mimumum frequency and maximum frequency are in Hz. + */ + struct UHD_API freq_range_t{ + double min, max; + freq_range_t(double min = 0.0, double max = 0.0); + }; + + /*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ + struct UHD_API tune_result_t{ + double target_inter_freq; + double actual_inter_freq; + double target_dxc_freq; + double actual_dxc_freq; + bool spectrum_inverted; + tune_result_t(void); + }; + + /*! + * Clock configuration settings: + * The source for the 10MHz reference clock. + * The source and polarity for the PPS clock. + * Possible settings for the reference and pps source + * are implementation specific motherboard properties. + * See the MBOARD_PROP_XXX_SOURCE_NAMES properties. + */ + struct clock_config_t{ + enum polarity_t {POLARITY_NEG, POLARITY_POS}; + std::string ref_source; + std::string pps_source; + polarity_t pps_polarity; + clock_config_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_HPP */ diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 995cb9926..e5333539f 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -18,10 +18,11 @@ #ifndef INCLUDED_UHD_UTILS_HPP #define INCLUDED_UHD_UTILS_HPP -#include -#include +#include #include #include +#include +#include /*! * Defines a function that implements the "construct on first use" idiom diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 875a065af..563ffb340 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -25,6 +25,7 @@ SET(libuhd_sources metadata.cpp simple_device.cpp time_spec.cpp + types.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp @@ -44,7 +45,7 @@ SET(libuhd_sources # Conditionally add the udp sources ######################################################################## LIST(APPEND libuhd_sources - transport/udp_zero_copy_none.cpp + transport/udp_zero_copy_asio.cpp ) ######################################################################## diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index 847bc0528..7dd1547cb 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -17,10 +17,12 @@ #include #include +#include #include #include #include #include +#include #include using namespace uhd; @@ -99,12 +101,10 @@ gain_t gain_handler_impl::get_overall_gain_val(void){ gain_range_t gain_handler_impl::get_overall_gain_range(void){ gain_t gain_min = 0, gain_max = 0, gain_step = 0; BOOST_FOREACH(std::string name, get_gain_names()){ - gain_t gain_min_tmp, gain_max_tmp, gain_step_tmp; - boost::tie(gain_min_tmp, gain_max_tmp, gain_step_tmp) = \ - get_named_prop(_props.range, name); - gain_min += gain_min_tmp; - gain_max += gain_max_tmp; - gain_step = std::max(gain_step, gain_step_tmp); + gain_range_t gain_tmp = get_named_prop(_props.range, name); + gain_min += gain_tmp.min; + gain_max += gain_tmp.max; + gain_step = std::max(gain_step, gain_tmp.step); } return gain_range_t(gain_min, gain_max, gain_step); } @@ -150,12 +150,10 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) //not a wildcard... dont handle (but check name and range) if (name != ""){ assert_has(get_gain_names(), name, "gain name"); - gain_t gain_min, gain_max, gain_step; - boost::tie(gain_min, gain_max, gain_step) = \ - get_named_prop(_props.range, name); - if (gain_val > gain_max or gain_val < gain_min) throw std::range_error(str( + gain_range_t gain = get_named_prop(_props.range, name); + if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str( boost::format("A value of %f for gain %s is out of range of (%f, %f)") - % gain_val % name % gain_min % gain_max + % gain_val % name % gain.min % gain.max )); return false; } @@ -163,14 +161,12 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) //set the overall gain BOOST_FOREACH(std::string name, get_gain_names()){ //get the min, max, step for this gain name - gain_t gain_min, gain_max, gain_step; - boost::tie(gain_min, gain_max, gain_step) = \ - get_named_prop(_props.range, name); + gain_range_t gain = get_named_prop(_props.range, name); //clip g to be within the allowed range - gain_t g = std::min(std::max(gain_val, gain_min), gain_max); + gain_t g = std::min(std::max(gain_val, gain.min), gain.max); //set g to be a multiple of the step size - g -= fmod(g, gain_step); + g -= std::fmod(g, gain.step); //set g to be the new gain _link[named_prop_t(_props.value, name)] = g; //subtract g out of the total gain left to apply diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index 79b035071..045318c6b 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,10 +28,6 @@ using namespace uhd; -tune_result_t::tune_result_t(void){ - /* NOP */ -} - /*********************************************************************** * Tune Helper Function **********************************************************************/ @@ -196,11 +193,8 @@ public: return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); } - std::vector get_rx_freq_range(void){ - std::vector range(2); - boost::tie(range[0], range[1]) = \ - _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); - return range; + freq_range_t get_rx_freq_range(void){ + return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); } void set_rx_gain(float gain){ @@ -211,11 +205,8 @@ public: return _rx_subdev[SUBDEV_PROP_GAIN].as(); } - std::vector get_rx_gain_range(void){ - std::vector range(3); - boost::tie(range[0], range[1], range[2]) = \ - _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); - return range; + gain_range_t get_rx_gain_range(void){ + return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); } void set_rx_antenna(const std::string &ant){ @@ -258,11 +249,8 @@ public: return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); } - std::vector get_tx_freq_range(void){ - std::vector range(2); - boost::tie(range[0], range[1]) = \ - _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); - return range; + freq_range_t get_tx_freq_range(void){ + return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); } void set_tx_gain(float gain){ @@ -273,11 +261,8 @@ public: return _tx_subdev[SUBDEV_PROP_GAIN].as(); } - std::vector get_tx_gain_range(void){ - std::vector range(3); - boost::tie(range[0], range[1], range[2]) = \ - _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); - return range; + gain_range_t get_tx_gain_range(void){ + return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); } void set_tx_antenna(const std::string &ant){ diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp new file mode 100644 index 000000000..219ae8720 --- /dev/null +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -0,0 +1,154 @@ +// +// 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 . +// + +#include +#include +#include +#include +#include + +using namespace uhd::transport; + +/*********************************************************************** + * Smart buffer implementation for udp zerocopy none + * + * This smart buffer implemention houses a const buffer. + * When the smart buffer is deleted, the buffer is freed. + * The memory in the const buffer is allocated with new [], + * and so the destructor frees the buffer with delete []. + **********************************************************************/ +class smart_buffer_impl : public smart_buffer{ +public: + smart_buffer_impl(const boost::asio::const_buffer &buff){ + _buff = buff; + } + + ~smart_buffer_impl(void){ + delete [] boost::asio::buffer_cast(_buff); + } + + const boost::asio::const_buffer &get(void) const{ + return _buff; + } + +private: + boost::asio::const_buffer _buff; +}; + +/*********************************************************************** + * UDP zero copy implementation class + * + * This is the portable zero copy implementation for systems + * where a faster, platform specific solution is not available. + * + * It uses boost asio udp sockets and the standard recv() class, + * and in-fact, is not actually doing a zero-copy implementation. + **********************************************************************/ +class udp_zero_copy_impl : public udp_zero_copy{ +public: + //structors + udp_zero_copy_impl(const std::string &addr, const std::string &port); + ~udp_zero_copy_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + smart_buffer::sptr recv(void); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::io_service _io_service; + + size_t get_recv_buff_size(void); + void set_recv_buff_size(size_t); +}; + +udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); + boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); + + // Create, open, and connect the socket + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + _socket->connect(receiver_endpoint); + + // set the rx socket buffer size: + // pick a huge size, and deal with whatever we get + set_recv_buff_size(size_t(54321e3)); //some big number! + size_t current_buff_size = get_recv_buff_size(); + std::cout << boost::format( + "Current rx socket buffer size: %d\n" + ) % current_buff_size; + if (current_buff_size < size_t(.1e6)) std::cout << boost::format( + "Adjust max rx socket buffer size (linux only):\n" + " sysctl -w net.core.rmem_max=VALUE\n" + ); +} + +udp_zero_copy_impl::~udp_zero_copy_impl(void){ + delete _socket; +} + +size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); +} + +smart_buffer::sptr udp_zero_copy_impl::recv(void){ + size_t available = 0; + + //implement timeout through polling and sleeping + boost::asio::deadline_timer timer(_socket->get_io_service()); + timer.expires_from_now(boost::posix_time::milliseconds(50)); + while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } + + //allocate memory and create buffer + boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; + boost::asio::mutable_buffer buff(buff_mem, available); + + //receive only if data is available + if (available){ + _socket->receive(boost::asio::buffer(buff)); + } + + //create a new smart buffer to house the data + return smart_buffer::sptr(new smart_buffer_impl(buff)); +} + +size_t udp_zero_copy_impl::get_recv_buff_size(void){ + boost::asio::socket_base::receive_buffer_size option; + _socket->get_option(option); + return option.value(); +} + +void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){ + boost::asio::socket_base::receive_buffer_size option(new_size); + _socket->set_option(option); +} + +/*********************************************************************** + * UDP zero copy make function + **********************************************************************/ +udp_zero_copy::sptr udp_zero_copy::make( + const std::string &addr, const std::string &port +){ + return sptr(new udp_zero_copy_impl(addr, port)); +} diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp deleted file mode 100644 index 219ae8720..000000000 --- a/host/lib/transport/udp_zero_copy_none.cpp +++ /dev/null @@ -1,154 +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 . -// - -#include -#include -#include -#include -#include - -using namespace uhd::transport; - -/*********************************************************************** - * Smart buffer implementation for udp zerocopy none - * - * This smart buffer implemention houses a const buffer. - * When the smart buffer is deleted, the buffer is freed. - * The memory in the const buffer is allocated with new [], - * and so the destructor frees the buffer with delete []. - **********************************************************************/ -class smart_buffer_impl : public smart_buffer{ -public: - smart_buffer_impl(const boost::asio::const_buffer &buff){ - _buff = buff; - } - - ~smart_buffer_impl(void){ - delete [] boost::asio::buffer_cast(_buff); - } - - const boost::asio::const_buffer &get(void) const{ - return _buff; - } - -private: - boost::asio::const_buffer _buff; -}; - -/*********************************************************************** - * UDP zero copy implementation class - * - * This is the portable zero copy implementation for systems - * where a faster, platform specific solution is not available. - * - * It uses boost asio udp sockets and the standard recv() class, - * and in-fact, is not actually doing a zero-copy implementation. - **********************************************************************/ -class udp_zero_copy_impl : public udp_zero_copy{ -public: - //structors - udp_zero_copy_impl(const std::string &addr, const std::string &port); - ~udp_zero_copy_impl(void); - - //send/recv - size_t send(const boost::asio::const_buffer &buff); - smart_buffer::sptr recv(void); - -private: - boost::asio::ip::udp::socket *_socket; - boost::asio::io_service _io_service; - - size_t get_recv_buff_size(void); - void set_recv_buff_size(size_t); -}; - -udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ - //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; - - // resolve the address - boost::asio::ip::udp::resolver resolver(_io_service); - boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); - boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); - - // Create, open, and connect the socket - _socket = new boost::asio::ip::udp::socket(_io_service); - _socket->open(boost::asio::ip::udp::v4()); - _socket->connect(receiver_endpoint); - - // set the rx socket buffer size: - // pick a huge size, and deal with whatever we get - set_recv_buff_size(size_t(54321e3)); //some big number! - size_t current_buff_size = get_recv_buff_size(); - std::cout << boost::format( - "Current rx socket buffer size: %d\n" - ) % current_buff_size; - if (current_buff_size < size_t(.1e6)) std::cout << boost::format( - "Adjust max rx socket buffer size (linux only):\n" - " sysctl -w net.core.rmem_max=VALUE\n" - ); -} - -udp_zero_copy_impl::~udp_zero_copy_impl(void){ - delete _socket; -} - -size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ - return _socket->send(boost::asio::buffer(buff)); -} - -smart_buffer::sptr udp_zero_copy_impl::recv(void){ - size_t available = 0; - - //implement timeout through polling and sleeping - boost::asio::deadline_timer timer(_socket->get_io_service()); - timer.expires_from_now(boost::posix_time::milliseconds(50)); - while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - } - - //allocate memory and create buffer - boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; - boost::asio::mutable_buffer buff(buff_mem, available); - - //receive only if data is available - if (available){ - _socket->receive(boost::asio::buffer(buff)); - } - - //create a new smart buffer to house the data - return smart_buffer::sptr(new smart_buffer_impl(buff)); -} - -size_t udp_zero_copy_impl::get_recv_buff_size(void){ - boost::asio::socket_base::receive_buffer_size option; - _socket->get_option(option); - return option.value(); -} - -void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){ - boost::asio::socket_base::receive_buffer_size option(new_size); - _socket->set_option(option); -} - -/*********************************************************************** - * UDP zero copy make function - **********************************************************************/ -udp_zero_copy::sptr udp_zero_copy::make( - const std::string &addr, const std::string &port -){ - return sptr(new udp_zero_copy_impl(addr, port)); -} diff --git a/host/lib/types.cpp b/host/lib/types.cpp new file mode 100644 index 000000000..f8a9a9b36 --- /dev/null +++ b/host/lib/types.cpp @@ -0,0 +1,57 @@ +// +// 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 . +// + +#include + +using namespace uhd; + +/*********************************************************************** + * gain range + **********************************************************************/ +gain_range_t::gain_range_t(float min_, float max_, float step_){ + min = min_; + max = max_; + step = step_; +} + +/*********************************************************************** + * freq range + **********************************************************************/ +freq_range_t::freq_range_t(double min_, double max_){ + min = min_; + max = max_; +} + +/*********************************************************************** + * tune result + **********************************************************************/ +tune_result_t::tune_result_t(void){ + target_inter_freq = 0.0; + actual_inter_freq = 0.0; + target_dxc_freq = 0.0; + actual_dxc_freq = 0.0; + spectrum_inverted = false; +} + +/*********************************************************************** + * clock config + **********************************************************************/ +clock_config_t::clock_config_t(void){ + ref_source = ""; //not a valid setting + pps_source = ""; //not a valid setting + pps_polarity = POLARITY_NEG; +} diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 02b391244..82485ae6a 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 4f63e6cc9..cbca8eec7 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -16,7 +16,6 @@ // #include -#include #include "usrp2_impl.hpp" using namespace uhd; @@ -36,21 +35,27 @@ void usrp2_impl::mboard_init(void){ } void usrp2_impl::init_clock_config(void){ + //init the ref source clock config + _ref_source_dict = boost::assign::map_list_of + ("int", USRP2_REF_SOURCE_INT) + ("sma", USRP2_REF_SOURCE_SMA) + ("mimo", USRP2_REF_SOURCE_MIMO) + ; + _clock_config.ref_source = "int"; + //init the pps source clock config - _pps_source_dict["sma"] = USRP2_PPS_SOURCE_SMA; - _pps_source_dict["mimo"] = USRP2_PPS_SOURCE_MIMO; - _pps_source = "sma"; + _pps_source_dict = boost::assign::map_list_of + ("sma", USRP2_PPS_SOURCE_SMA) + ("mimo", USRP2_PPS_SOURCE_MIMO) + ; + _clock_config.pps_source = "sma"; //init the pps polarity clock config - _pps_polarity_dict["pos"] = USRP2_PPS_POLARITY_POS; - _pps_polarity_dict["neg"] = USRP2_PPS_POLARITY_NEG; - _pps_polarity = "neg"; - - //init the ref source clock config - _ref_source_dict["int"] = USRP2_REF_SOURCE_INT; - _ref_source_dict["sma"] = USRP2_REF_SOURCE_SMA; - _ref_source_dict["mimo"] = USRP2_REF_SOURCE_MIMO; - _ref_source = "int"; + _pps_polarity_dict = boost::assign::map_list_of + (clock_config_t::POLARITY_POS, USRP2_PPS_POLARITY_POS) + (clock_config_t::POLARITY_NEG, USRP2_PPS_POLARITY_NEG) + ; + _clock_config.pps_polarity = clock_config_t::POLARITY_NEG; //update the clock config (sends a control packet) update_clock_config(); @@ -60,9 +65,9 @@ void usrp2_impl::update_clock_config(void){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_HERES_A_NEW_CLOCK_CONFIG_BRO); - out_data.data.clock_config.pps_source = _pps_source_dict [_pps_source]; - out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_pps_polarity]; - out_data.data.clock_config.ref_source = _ref_source_dict [_ref_source]; + out_data.data.clock_config.ref_source = _ref_source_dict [_clock_config.ref_source]; + out_data.data.clock_config.pps_source = _pps_source_dict [_clock_config.pps_source]; + out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_clock_config.pps_polarity]; //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -175,22 +180,14 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(_tx_dsps.get_keys()); return; - case MBOARD_PROP_PPS_SOURCE: - val = _pps_source; + case MBOARD_PROP_CLOCK_CONFIG: + val = _clock_config; return; case MBOARD_PROP_PPS_SOURCE_NAMES: val = prop_names_t(_pps_source_dict.get_keys()); return; - case MBOARD_PROP_PPS_POLARITY: - val = _pps_polarity; - return; - - case MBOARD_PROP_REF_SOURCE: - val = _ref_source; - return; - case MBOARD_PROP_REF_SOURCE_NAMES: val = prop_names_t(_ref_source_dict.get_keys()); return; @@ -237,26 +234,11 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ - case MBOARD_PROP_PPS_SOURCE:{ - std::string name = val.as(); - assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source"); - _pps_source = name; //shadow - update_clock_config(); - } - return; - - case MBOARD_PROP_PPS_POLARITY:{ - std::string name = val.as(); - assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity"); - _pps_polarity = name; //shadow - update_clock_config(); - } - return; - - case MBOARD_PROP_REF_SOURCE:{ - std::string name = val.as(); - assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source"); - _ref_source = name; //shadow + case MBOARD_PROP_CLOCK_CONFIG:{ + clock_config_t clock_config = val.as(); + assert_has(_pps_source_dict.get_keys(), clock_config.pps_source, "usrp2 pps source"); + assert_has(_ref_source_dict.get_keys(), clock_config.ref_source, "usrp2 ref source"); + _clock_config = clock_config; //shadow update_clock_config(); } return; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 59e23aba5..70420fd49 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -20,11 +20,12 @@ #include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -142,15 +143,15 @@ private: boost::mutex _ctrl_mutex; //methods and shadows for clock configuration - std::string _pps_source, _pps_polarity, _ref_source; + uhd::clock_config_t _clock_config; void init_clock_config(void); void update_clock_config(void); void set_time_spec(const uhd::time_spec_t &time_spec, bool now); //mappings from clock config strings to over the wire enums - uhd::dict _pps_source_dict; - uhd::dict _pps_polarity_dict; - uhd::dict _ref_source_dict; + uhd::dict _ref_source_dict; + uhd::dict _pps_source_dict; + uhd::dict _pps_polarity_dict; //rx and tx dboard methods and objects uhd::usrp::dboard_manager::sptr _dboard_manager; diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index a4005c0de..47acb30f0 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -108,12 +109,10 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ ); std::cout << "verifying the overall min, max, step" << std::endl; - gain_t gain_min, gain_max, gain_step; - boost::tie(gain_min, gain_max, gain_step) = \ - go0[PROP_GAIN_RANGE].as(); - BOOST_CHECK_EQUAL(gain_min, gain_t(-10)); - BOOST_CHECK_EQUAL(gain_max, gain_t(100)); - BOOST_CHECK_EQUAL(gain_step, gain_t(1.5)); + gain_range_t gain = go0[PROP_GAIN_RANGE].as(); + BOOST_CHECK_EQUAL(gain.min, gain_t(-10)); + BOOST_CHECK_EQUAL(gain.max, gain_t(100)); + BOOST_CHECK_EQUAL(gain.step, gain_t(1.5)); std::cout << "verifying the overall gain" << std::endl; go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = gain_t(-5); -- cgit v1.2.3