diff options
Diffstat (limited to 'host/lib/usrp/usrp1')
-rw-r--r-- | host/lib/usrp/usrp1/io_impl.cpp | 202 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.cpp | 52 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.hpp | 17 |
3 files changed, 125 insertions, 146 deletions
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index aee760a83..6728d9b15 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,33 +33,26 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; +static const size_t alignment_padding = 512; + /*********************************************************************** - * Pseudo send buffer implementation + * Helper struct to associate an offset with a buffer **********************************************************************/ -class pseudo_managed_send_buffer : public managed_send_buffer{ +class offset_send_buffer{ public: + typedef boost::shared_ptr<offset_send_buffer> sptr; - pseudo_managed_send_buffer( - const boost::asio::mutable_buffer &buff, - const boost::function<ssize_t(size_t)> &commit - ): - _buff(buff), - _commit(commit) - { - /* NOP */ + static sptr make(managed_send_buffer::sptr buff, size_t offset = 0){ + return sptr(new offset_send_buffer(buff, offset)); } - ssize_t commit(size_t num_bytes){ - return _commit(num_bytes); - } + //member variables + managed_send_buffer::sptr buff; + size_t offset; /* in bytes */ private: - const boost::asio::mutable_buffer &get(void) const{ - return _buff; - } - - const boost::asio::mutable_buffer _buff; - const boost::function<ssize_t(size_t)> _commit; + offset_send_buffer(managed_send_buffer::sptr buff, size_t offset): + buff(buff), offset(offset){/* NOP */} }; /*********************************************************************** @@ -70,8 +63,8 @@ struct usrp1_impl::io_impl{ data_transport(data_transport), underflow_poll_samp_count(0), overflow_poll_samp_count(0), - send_buff(data_transport->get_send_buff()), - num_bytes_committed(0) + curr_buff_committed(true), + curr_buff(offset_send_buffer::make(data_transport->get_send_buff())) { /* NOP */ } @@ -91,100 +84,91 @@ struct usrp1_impl::io_impl{ size_t overflow_poll_samp_count; //wrapper around the actual send buffer interface - //all of this to ensure only full buffers are committed - managed_send_buffer::sptr send_buff; - size_t num_bytes_committed; - boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; - ssize_t phony_commit_pseudo_buff(size_t num_bytes); - ssize_t phony_commit_send_buff(size_t num_bytes); - ssize_t commit_send_buff(void); + //all of this to ensure only aligned lengths are committed + //NOTE: you must commit before getting a new buffer + //since the vrt packet handler obeys this, we are ok + bool curr_buff_committed; + offset_send_buffer::sptr curr_buff; + void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t); void flush_send_buff(void); - bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &); - - //helpers to get at the send buffer + offset - inline void *get_send_mem_ptr(void){ - return send_buff->cast<boost::uint8_t *>() + num_bytes_committed; - } - inline size_t get_send_mem_size(void){ - return send_buff->size() - num_bytes_committed; - } + bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); }; /*! - * Accept a commit of num bytes to the pseudo buffer. - * Memcpy the entire contents of pseudo buffer into send buffers. - * - * Under most conditions: - * The first loop iteration will fill the remainder of the send buffer. - * The second loop iteration will empty the pseudo buffer remainder. + * Perform an actual commit on the send buffer: + * Copy the remainder of alignment to the next buffer. + * Commit the current buffer at multiples of alignment. */ -ssize_t usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ - size_t bytes_to_copy = num_bytes, bytes_copied = 0; - while(bytes_to_copy){ - size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size()); - std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here); - ssize_t ret = phony_commit_send_buff(bytes_copied_here); - if (ret < 0) return ret; - bytes_to_copy -= ret; - bytes_copied += ret; - } - return bytes_copied; -} +void usrp1_impl::io_impl::commit_send_buff( + offset_send_buffer::sptr curr, + offset_send_buffer::sptr next, + size_t num_bytes +){ + //total number of bytes now in the current buffer + size_t bytes_in_curr_buffer = curr->offset + num_bytes; + + //calculate how many to commit and remainder + size_t num_bytes_remaining = bytes_in_curr_buffer % alignment_padding; + size_t num_bytes_to_commit = bytes_in_curr_buffer - num_bytes_remaining; + + //copy the remainder into the next buffer + std::memcpy( + next->buff->cast<char *>() + next->offset, + curr->buff->cast<char *>() + num_bytes_to_commit, + num_bytes_remaining + ); -/*! - * Accept a commit of num bytes to the send buffer. - * Conditionally commit the send buffer if full. - */ -ssize_t usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ - num_bytes_committed += num_bytes; - if (num_bytes_committed != send_buff->size()) return num_bytes; - ssize_t ret = commit_send_buff(); - return (ret < 0)? ret : num_bytes; + //update the offset into the next buffer + next->offset += num_bytes_remaining; + + //commit the current buffer + curr->buff->commit(num_bytes_to_commit); + curr_buff_committed = true; } /*! - * Flush the send buffer: - * Zero-pad the send buffer to the nearest 512 byte boundary and commit. + * Flush the current buffer by padding out to alignment and committing. */ void usrp1_impl::io_impl::flush_send_buff(void){ - size_t bytes_to_pad = (-1*num_bytes_committed)%512; - std::memset(get_send_mem_ptr(), 0, bytes_to_pad); - num_bytes_committed += bytes_to_pad; - commit_send_buff(); + //calculate the number of bytes to alignment + size_t bytes_to_pad = (-1*curr_buff->offset)%alignment_padding; + + //get the buffer, clear, and commit (really current buffer) + vrt_packet_handler::managed_send_buffs_t buffs(1); + if (this->get_send_buffs(buffs, 0.1)){ + std::memset(buffs[0]->cast<void *>(), 0, bytes_to_pad); + buffs[0]->commit(bytes_to_pad); + } } /*! - * Perform an actual commit on the send buffer: - * Commit the contents of the send buffer and request a new buffer. + * Get a managed send buffer with the alignment padding: + * Always grab the next send buffer so we can timeout here. */ -ssize_t usrp1_impl::io_impl::commit_send_buff(void){ - ssize_t ret = send_buff->commit(num_bytes_committed); - send_buff = data_transport->get_send_buff(); - num_bytes_committed = 0; - return ret; -} - bool usrp1_impl::io_impl::get_send_buffs( - vrt_packet_handler::managed_send_buffs_t &buffs + vrt_packet_handler::managed_send_buffs_t &buffs, double timeout ){ - UHD_ASSERT_THROW(buffs.size() == 1); + UHD_ASSERT_THROW(curr_buff_committed and buffs.size() == 1); + + //try to get a new managed buffer with timeout + offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout))); + if (not next_buff->buff.get()) return false; /* propagate timeout here */ + + //calculate the buffer pointer and size given the offset + //references to the buffers are held in the bound function + buffs[0] = managed_send_buffer::make_safe( + boost::asio::buffer( + curr_buff->buff->cast<char *>() + curr_buff->offset, + curr_buff->buff->size() - curr_buff->offset + ), + boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, curr_buff, next_buff, _1) + ); - //not enough bytes free -> use the pseudo buffer - if (get_send_mem_size() < BYTES_PER_PACKET){ - buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( - boost::asio::buffer(pseudo_buff), - boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1) - )); - } - //otherwise use the send buffer offset by the bytes written - else{ - buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( - boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), - boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) - )); - } + //store the next buffer for the next call + curr_buff = next_buff; + curr_buff_committed = false; - return buffs[0].get() != NULL; + return true; } /*********************************************************************** @@ -213,10 +197,17 @@ static void usrp1_bs_vrt_packer( if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32; } +size_t usrp1_impl::get_max_send_samps_per_packet(void) const { + return (_data_transport->get_send_frame_size() - alignment_padding) + / _tx_otw_type.get_sample_size() + / _tx_subdev_spec.size() + ; +} + size_t usrp1_impl::send( const std::vector<const void *> &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, double timeout ){ size_t num_samps_sent = vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler @@ -225,7 +216,7 @@ size_t usrp1_impl::send( io_type, _tx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_packer, - boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1), + boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1, timeout), get_max_send_samps_per_packet(), 0, //vrt header offset _tx_subdev_spec.size() //num channels @@ -272,18 +263,25 @@ static void usrp1_bs_vrt_unpacker( } static bool get_recv_buffs( - zero_copy_if::sptr zc_if, size_t timeout_ms, + zero_copy_if::sptr zc_if, double timeout, vrt_packet_handler::managed_recv_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = zc_if->get_recv_buff(timeout_ms); + buffs[0] = zc_if->get_recv_buff(timeout); return buffs[0].get() != NULL; } +size_t usrp1_impl::get_max_recv_samps_per_packet(void) const { + return _data_transport->get_recv_frame_size() + / _rx_otw_type.get_sample_size() + / _rx_subdev_spec.size() + ; +} + size_t usrp1_impl::recv( const std::vector<void *> &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, size_t timeout_ms + recv_mode_t recv_mode, double timeout ){ size_t num_samps_recvd = vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler @@ -292,7 +290,7 @@ size_t usrp1_impl::recv( io_type, _rx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_unpacker, - boost::bind(&get_recv_buffs, _data_transport, timeout_ms, _1), + boost::bind(&get_recv_buffs, _data_transport, timeout, _1), &vrt_packet_handler::handle_overflow_nop, 0, //vrt header offset _rx_subdev_spec.size() //num channels diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 156fc119f..276ca86f6 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -106,17 +106,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) /*********************************************************************** * Make **********************************************************************/ -template<typename output_type> static output_type cast_from_dev_addr( - const device_addr_t &device_addr, - const std::string &key, - output_type def_val -){ - return (device_addr.has_key(key))? - boost::lexical_cast<output_type>(device_addr[key]) : def_val; -} +static device::sptr usrp1_make(const device_addr_t &device_addr){ -static device::sptr usrp1_make(const device_addr_t &device_addr) -{ //extract the FPGA path for the USRP1 std::string usrp1_fpga_image = find_image_path( device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" @@ -127,29 +118,26 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(USRP1_VENDOR_ID, USRP1_PRODUCT_ID); - //create data and control transports - usb_zero_copy::sptr data_transport; - usrp_ctrl::sptr usrp_ctrl; - - - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_serial() == device_addr["serial"]) { - usb_control::sptr ctrl_transport = usb_control::make(handle); - usrp_ctrl = usrp_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - - data_transport = usb_zero_copy::make( - handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - size_t(cast_from_dev_addr<double>(device_addr, "recv_xfer_size", 0)), - size_t(cast_from_dev_addr<double>(device_addr, "recv_num_xfers", 0)), - size_t(cast_from_dev_addr<double>(device_addr, "send_xfer_size", 0)), - size_t(cast_from_dev_addr<double>(device_addr, "send_num_xfers", 0)) - ); + //locate the matching handle in the device list + usb_device_handle::sptr handle; + BOOST_FOREACH(usb_device_handle::sptr dev_handle, device_list) { + if (dev_handle->get_serial() == device_addr["serial"]){ + handle = dev_handle; break; } } + UHD_ASSERT_THROW(handle.get() != NULL); //better be found + + //create control objects and a data transport + usb_control::sptr ctrl_transport = usb_control::make(handle); + usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); + usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); + usb_zero_copy::sptr data_transport = usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + device_addr // param hints + ); //create the usrp1 implementation guts return device::sptr(new usrp1_impl(data_transport, usrp_ctrl)); @@ -209,9 +197,9 @@ usrp1_impl::~usrp1_impl(void){ /* NOP */ } -bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, size_t timeout_ms){ +bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, double timeout){ //dummy fill-in for the recv_async_msg - boost::this_thread::sleep(boost::posix_time::milliseconds(timeout_ms)); + boost::this_thread::sleep(boost::posix_time::microseconds(long(timeout*1e6))); return false; } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 20ae3c02a..ff4d40762 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -83,25 +83,18 @@ public: size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, - send_mode_t); + send_mode_t, double); size_t recv(const std::vector<void *> &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, - recv_mode_t, - size_t timeout); + recv_mode_t, double); - static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size + size_t get_max_send_samps_per_packet(void) const; - size_t get_max_send_samps_per_packet(void) const { - return BYTES_PER_PACKET/_tx_otw_type.get_sample_size()/_tx_subdev_spec.size(); - } - - size_t get_max_recv_samps_per_packet(void) const { - return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size(); - } + size_t get_max_recv_samps_per_packet(void) const; - bool recv_async_msg(uhd::async_metadata_t &, size_t); + bool recv_async_msg(uhd::async_metadata_t &, double); private: /*! |