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 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