diff options
author | Josh Blum <josh@joshknows.com> | 2010-03-15 17:00:04 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-03-15 17:00:04 +0000 |
commit | 1bfb556262d12740c71e68a2a071e6e67ed2b3e7 (patch) | |
tree | a081bfd3a61ccb42372a627be7b57ce19a3baa0d /host/lib/usrp/usrp2/io_impl.cpp | |
parent | 1b965831ae7588c7879d84de4e5fbd78ca614761 (diff) | |
parent | fc40ff2f1327d01c72c4d7dbc07a14e473251981 (diff) | |
download | uhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.tar.gz uhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.tar.bz2 uhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.zip |
Merge branch 'master' of git@ettus.sourcerepo.com:ettus/uhd into u1e_uhd
Conflicts:
host/apps/CMakeLists.txt
host/lib/usrp/usrp2/usrp2_impl.cpp
Diffstat (limited to 'host/lib/usrp/usrp2/io_impl.cpp')
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 329 |
1 files changed, 172 insertions, 157 deletions
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 43334ddc6..cc7746720 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,12 +16,13 @@ // #include <complex> -#include <boost/shared_array.hpp> #include <boost/format.hpp> #include "usrp2_impl.hpp" using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; +namespace asio = boost::asio; /*********************************************************************** * Constants @@ -29,214 +30,228 @@ using namespace uhd::usrp; typedef std::complex<float> fc32_t; typedef std::complex<int16_t> 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; +static const float shorts_per_float = pow(2.0, 15); +static const float floats_per_short = 1.0/shorts_per_float; /*********************************************************************** * Helper Functions **********************************************************************/ -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)); - } +void usrp2_impl::io_init(void){ + //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(asio::buffer(&zero_data, sizeof(zero_data))); +} + +#define unrolled_loop(__i, __len, __inst) {\ + size_t __i = 0; \ + while(__i < (__len & ~0x7)){ \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + } \ + while(__i < __len){ \ + __inst; __i++;\ + } \ } -static inline void usrp2_shorts_to_host_floats( - float *host_floats, - const int16_t *usrp2_shorts, +// 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, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor); - } + 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; + usrp2_items[i] = htonl((real << 16) | (imag << 0)); + }); } -static inline void host_shorts_to_usrp2_shorts( - int16_t *usrp2_shorts, - const int16_t *host_shorts, +static inline void usrp2_items_to_host_floats( + fc32_t *host_floats, + const uint32_t *usrp2_items, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - usrp2_shorts[i] = htons(host_shorts[i]); - } + 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); + }); } -static inline void usrp2_shorts_to_host_shorts( - int16_t *host_shorts, - const int16_t *usrp2_shorts, +static inline void host_items_to_usrp2_items( + uint32_t *usrp2_items, + const uint32_t *host_items, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - host_shorts[i] = ntohs(usrp2_shorts[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])); } } -/*********************************************************************** - * Send Raw Data - **********************************************************************/ -size_t usrp2_impl::send_raw( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata +static inline void usrp2_items_to_host_items( + uint32_t *host_items, + const uint32_t *usrp2_items, + size_t num_samps ){ - std::vector<boost::asio::const_buffer> 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 (is_big_endian){ + std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t)); } - 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 + else{ + unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); } - 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]++ & 0xf) << 16) | - ((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<boost::asio::mutable_buffer> buffs(2); - uint32_t vrt_hdr[max_vrt_header_words]; - buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words); - buffs[1] = buff; +void usrp2_impl::recv_raw(rx_metadata_t &metadata){ + //do a receive + _rx_smart_buff = _data_transport->recv(); - //receive into the buffers - size_t bytes_recvd = _data_transport->recv(buffs); + //unpack the vrt header + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(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<const uint32_t *>(_rx_smart_buff->get()); + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + try{ + vrt::unpack( + metadata, //output + vrt_hdr, //input + num_header_words32_out, //output + num_payload_words32_out, //output + num_packet_words32, //input + packet_count_out //output + ); + }catch(const std::exception &e){ + std::cerr << "bad vrt header: " << e.what() << std::endl; + _rx_copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } - //failure case - if (bytes_recvd < max_vrt_header_words*sizeof(uint32_t)) return 0; + //handle the packet count / sequence number + size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != expected_packet_count){ + std::cerr << "bad packet count: " << packet_count_out << std::endl; + } + _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16; - //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); + //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) + ); } /*********************************************************************** * 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 ){ - if (type == "fc32"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); - boost::shared_array<sc16_t> 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<int16_t*>(raw_buff), - boost::asio::buffer_cast<const float*>(buff), - num_samps*2 //double for complex - ); - - return send_raw(raw_buff, metadata); + 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 + 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<const fc32_t*>(buff), num_samps); + } + 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<const uint32_t*>(buff), num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - 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<sc16_t> 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<int16_t*>(raw_buff), - boost::asio::buffer_cast<const int16_t*>(buff), - num_samps*2 //double for complex - ); + 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 + ); - return send_raw(raw_buff, metadata); - #endif - } + //copy in the vrt header (yes we left space) + items -= num_header_words32; + std::memcpy(items, vrt_hdr, num_header_words32*sizeof(uint32_t)); - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); + //send and return number of samples + _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(uint32_t))); + return num_samps; } /*********************************************************************** * 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 ){ - if (type == "fc32"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); - boost::shared_array<sc16_t> 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<float*>(buff), - boost::asio::buffer_cast<const int16_t*>(raw_buff), - num_samps*2 //double for complex - ); - - return num_samps; + //perform a receive if no rx data is waiting to be copied + 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; } - 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<sc16_t> 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<int16_t*>(buff), - boost::asio::buffer_cast<const int16_t*>(raw_buff), - num_samps*2 //double for complex - ); - - return num_samps; - #endif + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); + if (bytes_to_copy == 0) return 0; //nothing to receive + size_t num_samps = bytes_to_copy/sizeof(uint32_t); + const uint32_t *items = asio::buffer_cast<const uint32_t*>(_rx_copy_buff); + + //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<fc32_t*>(buff), items, num_samps); + } + 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<uint32_t*>(buff), items, num_samps); } + else{ + 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, bytes_to_copy - num_samps*sizeof(uint32_t) + ); - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); + return num_samps; } |