diff options
author | Josh Blum <josh@joshknows.com> | 2012-02-17 18:18:26 -0800 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2012-02-17 18:18:26 -0800 |
commit | 3ddbcb6078593c39cb0e4bc8f9769f818a61466f (patch) | |
tree | 408e3f6a64e31b7d830b9f884ecebdaf100a5d2d /host/lib/transport/usb_zero_copy_wrapper.cpp | |
parent | 1fab7e9d477aa98e489400c25a08358952c69c90 (diff) | |
parent | ace4489066d1621a09e70650a00d736f0b03ed8c (diff) | |
download | uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.gz uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.bz2 uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.zip |
Merge branch 'next'
Diffstat (limited to 'host/lib/transport/usb_zero_copy_wrapper.cpp')
-rw-r--r-- | host/lib/transport/usb_zero_copy_wrapper.cpp | 106 |
1 files changed, 51 insertions, 55 deletions
diff --git a/host/lib/transport/usb_zero_copy_wrapper.cpp b/host/lib/transport/usb_zero_copy_wrapper.cpp index 227c4b392..690e5aaa2 100644 --- a/host/lib/transport/usb_zero_copy_wrapper.cpp +++ b/host/lib/transport/usb_zero_copy_wrapper.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -18,17 +18,13 @@ #include <uhd/transport/usb_zero_copy.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <uhd/transport/buffer_pool.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/msg.hpp> #include <boost/foreach.hpp> #include <vector> #include <iostream> using namespace uhd::transport; -bool debug = true; - -static inline size_t next_boundary(size_t length, size_t boundary){ - //pad to the boundary, assumes boundary is a power of 2 - return (length + (boundary-1)) & ~(boundary-1); -} /*********************************************************************** * USB zero copy wrapper - managed receive buffer @@ -45,7 +41,7 @@ public: _mrb.reset(); } - sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){ + UHD_INLINE sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){ _mrb = mrb; _mem = mem; _len = len; @@ -67,28 +63,46 @@ private: **********************************************************************/ class usb_zero_copy_wrapper_msb : public managed_send_buffer{ public: - usb_zero_copy_wrapper_msb(bounded_buffer<usb_zero_copy_wrapper_msb *> &queue, size_t boundary): - _queue(queue), _boundary(boundary){/*NOP*/} + usb_zero_copy_wrapper_msb(const usb_zero_copy::sptr internal, const size_t fragmentation_size): + _internal(internal), _fragmentation_size(fragmentation_size){/*NOP*/} void commit(size_t len){ - if (_msb.get() == NULL) return; - _msb->commit(next_boundary(len, _boundary)); - _queue.push_with_haste(this); - _msb.reset(); + if (len == 0) return; + + //get a reference to the VITA header before incrementing + const boost::uint32_t vita_header = reinterpret_cast<const boost::uint32_t *>(_mem_buffer_tip)[0]; + + _bytes_in_buffer += len; + _mem_buffer_tip += len; + + //extract VITA end of packet flag, we must force flush under eof conditions + const bool eop = (uhd::wtohx(vita_header) & (0x1 << 24)) != 0; + const bool full = _bytes_in_buffer >= (_last_send_buff->size() - _fragmentation_size); + if (eop or full){ + _last_send_buff->commit(_bytes_in_buffer); + _last_send_buff.reset(); + } } - sptr get_new(managed_send_buffer::sptr msb){ - _msb = msb; + UHD_INLINE sptr get_new(const double timeout){ + if (not _last_send_buff){ + _last_send_buff = _internal->get_send_buff(timeout); + if (not _last_send_buff) return sptr(); + _mem_buffer_tip = _last_send_buff->cast<char *>(); + _bytes_in_buffer = 0; + } return make_managed_buffer(this); } private: - void *get_buff(void) const{return _msb->cast<void *>();} - size_t get_size(void) const{return _msb->size();} - - bounded_buffer<usb_zero_copy_wrapper_msb *> &_queue; - size_t _boundary; - managed_send_buffer::sptr _msb; + void *get_buff(void) const{return reinterpret_cast<void *>(_mem_buffer_tip);} + size_t get_size(void) const{return _fragmentation_size;} + + usb_zero_copy::sptr _internal; + const size_t _fragmentation_size; + managed_send_buffer::sptr _last_send_buff; + size_t _bytes_in_buffer; + char *_mem_buffer_tip; }; /*********************************************************************** @@ -96,23 +110,16 @@ private: **********************************************************************/ class usb_zero_copy_wrapper : public usb_zero_copy{ public: - usb_zero_copy_wrapper( - sptr usb_zc, size_t usb_frame_boundary - ): + usb_zero_copy_wrapper(sptr usb_zc, const size_t frame_boundary): _internal_zc(usb_zc), - _usb_frame_boundary(usb_frame_boundary), + _frame_boundary(frame_boundary), _available_recv_buffs(this->get_num_recv_frames()), - _available_send_buffs(this->get_num_send_frames()), _mrb_pool(this->get_num_recv_frames(), usb_zero_copy_wrapper_mrb(_available_recv_buffs)), - _msb_pool(this->get_num_send_frames(), usb_zero_copy_wrapper_msb(_available_send_buffs, usb_frame_boundary)) + _the_only_msb(usb_zero_copy_wrapper_msb(usb_zc, frame_boundary)) { BOOST_FOREACH(usb_zero_copy_wrapper_mrb &mrb, _mrb_pool){ _available_recv_buffs.push_with_haste(&mrb); } - - BOOST_FOREACH(usb_zero_copy_wrapper_msb &msb, _msb_pool){ - _available_send_buffs.push_with_haste(&msb); - } } managed_recv_buffer::sptr get_recv_buff(double timeout){ @@ -128,18 +135,17 @@ public: //extract this packet's memory address and length in bytes const char *mem = _last_recv_buff->cast<const char *>() + _last_recv_offset; const boost::uint32_t *mem32 = reinterpret_cast<const boost::uint32_t *>(mem); - size_t len = (mem32[0] & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header) - + const size_t len = (uhd::wtohx(mem32[0]) & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header) + managed_recv_buffer::sptr recv_buff; //the buffer to be returned to the user - recv_buff = wmrb->get_new(_last_recv_buff, mem, len); - _last_recv_offset = next_boundary(_last_recv_offset + len, _usb_frame_boundary); - + _last_recv_offset += len; + //check if this receive buffer has been exhausted if (_last_recv_offset >= _last_recv_buff->size()) { _last_recv_buff.reset(); } - + return recv_buff; } @@ -152,20 +158,11 @@ public: } size_t get_recv_frame_size(void) const{ - return _internal_zc->get_recv_frame_size(); + return std::min(_frame_boundary, _internal_zc->get_recv_frame_size()); } managed_send_buffer::sptr get_send_buff(double timeout){ - managed_send_buffer::sptr send_buff = _internal_zc->get_send_buff(timeout); - - //attempt to get a wrapper for a managed send buffer - usb_zero_copy_wrapper_msb *wmsb = NULL; - if (send_buff.get() and _available_send_buffs.pop_with_haste(wmsb)){ - return wmsb->get_new(send_buff); - } - - //otherwise return a null sptr for failure - return managed_send_buffer::sptr(); + return _the_only_msb.get_new(timeout); } size_t get_num_send_frames(void) const{ @@ -173,20 +170,19 @@ public: } size_t get_send_frame_size(void) const{ - return _internal_zc->get_send_frame_size(); + return std::min(_frame_boundary, _internal_zc->get_send_frame_size()); } private: sptr _internal_zc; - size_t _usb_frame_boundary; + size_t _frame_boundary; bounded_buffer<usb_zero_copy_wrapper_mrb *> _available_recv_buffs; - bounded_buffer<usb_zero_copy_wrapper_msb *> _available_send_buffs; std::vector<usb_zero_copy_wrapper_mrb> _mrb_pool; - std::vector<usb_zero_copy_wrapper_msb> _msb_pool; - + usb_zero_copy_wrapper_msb _the_only_msb; + //buffer to store partially-received VRT packets in buffer_pool::sptr _fragment_mem; - + //state for last recv buffer to create multiple managed buffers managed_recv_buffer::sptr _last_recv_buff; size_t _last_recv_offset; |