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/udp.cpp') 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/udp.cpp') 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/udp.cpp') 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