diff options
author | Josh Blum <josh@joshknows.com> | 2010-07-06 17:09:50 -0700 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-07-06 17:09:50 -0700 |
commit | 01067698803179cf8021d30c881eb16f17b184db (patch) | |
tree | 0176e1238fb06b639a3a8fdaa471c35044712c14 /host/lib/usrp/usrp2/io_impl.cpp | |
parent | 7bf4370762087eeb2e590414869f53c90c70398d (diff) | |
parent | 7f3c4791f7d19d02b7d4515c763b9c2044e96170 (diff) | |
download | uhd-01067698803179cf8021d30c881eb16f17b184db.tar.gz uhd-01067698803179cf8021d30c881eb16f17b184db.tar.bz2 uhd-01067698803179cf8021d30c881eb16f17b184db.zip |
Merge branch 'usrp2_mimo'
Diffstat (limited to 'host/lib/usrp/usrp2/io_impl.cpp')
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 195 |
1 files changed, 114 insertions, 81 deletions
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index aa0f63321..c96528694 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -20,7 +20,7 @@ #include "usrp2_regs.hpp" #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/convert_types.hpp> -#include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/alignment_buffer.hpp> #include <boost/format.hpp> #include <boost/asio.hpp> //htonl and ntohl #include <boost/bind.hpp> @@ -34,56 +34,81 @@ namespace asio = boost::asio; /*********************************************************************** * io impl details (internal to this file) + * - pirate crew + * - alignment buffer + * - thread loop + * - vrt packet handler states **********************************************************************/ struct usrp2_impl::io_impl{ + typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type; - io_impl(zero_copy_if::sptr zc_if); - ~io_impl(void); + io_impl(size_t num_frames, size_t width): + packet_handler_recv_state(width), + recv_pirate_booty(alignment_buffer_type::make(num_frames, width)) + { + /* NOP */ + } + + ~io_impl(void){ + recv_pirate_crew_raiding = false; + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); + } - managed_recv_buffer::sptr get_recv_buff(void); + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); + } //state management for the vrt packet handler code vrt_packet_handler::recv_state packet_handler_recv_state; vrt_packet_handler::send_state packet_handler_send_state; - //methods and variables for the recv pirate - void recv_pirate_loop(zero_copy_if::sptr zc_if); - boost::thread *recv_pirate_thread; bool recv_pirate_running; - bounded_buffer<managed_recv_buffer::sptr>::sptr recv_pirate_booty; + //methods and variables for the pirate crew + void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t); + boost::thread_group recv_pirate_crew; + bool recv_pirate_crew_raiding; + alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if){ - //create a large enough booty - size_t num_frames = zc_if->get_num_recv_frames(); - std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = bounded_buffer<managed_recv_buffer::sptr>::make(num_frames); - - //create a new pirate thread (yarr!!) - recv_pirate_thread = new boost::thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_if) - ); -} - -usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_running = false; - recv_pirate_thread->interrupt(); - recv_pirate_thread->join(); - delete recv_pirate_thread; -} - -managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){ - managed_recv_buffer::sptr buff; - boost::this_thread::disable_interruption di; //disable because the wait can throw - recv_pirate_booty->pop_with_timed_wait(buff, boost::posix_time::milliseconds(100)); - return buff; //a timeout means that we return a null sptr... -} - -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ +/*********************************************************************** + * Receive Pirate Loop + * - while raiding, loot for recv buffers + * - put booty into the alignment buffer + **********************************************************************/ +void usrp2_impl::io_impl::recv_pirate_loop( + zero_copy_if::sptr zc_if, + usrp2_mboard_impl::sptr mboard, + size_t index +){ set_thread_priority_safe(); - recv_pirate_running = true; - while(recv_pirate_running){ + recv_pirate_crew_raiding = true; + while(recv_pirate_crew_raiding){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff); + if (buff->size() == 0) continue; //ignore timeout buffers + + try{ + //extract the vrt header packet info + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); + vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info); + + //extract the timespec and round to the nearest packet + UHD_ASSERT_THROW(if_packet_info.has_tsi and if_packet_info.has_tsf); + + //size_t pkt_dur_ticks = mboard->get_master_clock_freq() * 1; //TODO FIXME + //size_t(if_packet_info.tsf) - size_t(if_packet_info.tsf)%pkt_dur_ticks + //the idea is to round the time specs to packet boundaries to avoid the issue + //of never getting alignment when things are not locked properly + time_spec_t time( + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() + ); + + //push the packet into the buffer with the new time + recv_pirate_booty->push_with_pop_on_full(buff, time, index); + }catch(const std::exception &e){ + std::cerr << "Error (usrp2 recv pirate loop): " << e.what() << std::endl; + } } } @@ -91,58 +116,64 @@ void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //setup rx otw type - _rx_otw_type.width = 16; - _rx_otw_type.shift = 0; - _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //send a small data packet so the usrp2 knows the udp source port + for(size_t i = 0; i < _data_transports.size(); i++){ + managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff(); + boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); + memcpy(send_buff->cast<void*>(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); + } - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //the number of recv frames is the number for the first transport + //the assumption is that all data transports should be identical + size_t num_frames = _data_transports.front()->get_num_recv_frames(); - //send a small data packet so the usrp2 knows the udp source port - managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); - boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); - memcpy(send_buff->cast<void*>(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); + //create new io impl + _io_impl = UHD_PIMPL_MAKE(io_impl, (num_frames, _data_transports.size())); + + //create a new pirate thread for each zc if (yarr!!) + for (size_t i = 0; i < _data_transports.size(); i++){ + _io_impl->recv_pirate_crew.create_thread(boost::bind( + &usrp2_impl::io_impl::recv_pirate_loop, + _io_impl, _data_transports.at(i), + _mboards.at(i), i + )); + } - //setup RX DSP regs std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); - _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset - _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); - _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); - std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; - - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + std::cout << "Recv pirate num frames: " << num_frames << std::endl; } /*********************************************************************** * Send Data **********************************************************************/ +bool get_send_buffs( + const std::vector<udp_zero_copy::sptr> &trans, + vrt_packet_handler::managed_send_buffs_t &buffs +){ + UHD_ASSERT_THROW(trans.size() == buffs.size()); + for (size_t i = 0; i < buffs.size(); i++){ + buffs[i] = trans[i]->get_send_buff(); + } + return true; +} + size_t usrp2_impl::send( - const asio::const_buffer &buff, + 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 ){ return vrt_packet_handler::send( - _io_impl->packet_handler_send_state, //last state of the send handler - buff, metadata, send_mode, //buffer to empty and samples metadata - io_type, _tx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate - uhd::transport::vrt::pack_be, - boost::bind(&zero_copy_if::get_send_buff, _data_transport), + _io_impl->packet_handler_send_state, //last state of the send handler + buffs, num_samps, //buffer to fill + metadata, send_mode, //samples metadata + io_type, _io_helper.get_tx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate + uhd::transport::vrt::if_hdr_pack_be, + boost::bind(&get_send_buffs, _data_transports, _1), get_max_send_samps_per_packet() ); } @@ -151,17 +182,19 @@ size_t usrp2_impl::send( * Receive Data **********************************************************************/ size_t usrp2_impl::recv( - const asio::mutable_buffer &buff, + const std::vector<void *> &buffs, + size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode ){ return vrt_packet_handler::recv( - _io_impl->packet_handler_recv_state, //last state of the recv handler - buff, metadata, recv_mode, //buffer to fill and samples metadata - io_type, _rx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate - uhd::transport::vrt::unpack_be, - boost::bind(&usrp2_impl::io_impl::get_recv_buff, _io_impl) + _io_impl->packet_handler_recv_state, //last state of the recv handler + buffs, num_samps, //buffer to fill + metadata, recv_mode, //samples metadata + io_type, _io_helper.get_rx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate + uhd::transport::vrt::if_hdr_unpack_be, + boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl, _1) ); } |