From 08fad28f209a2f6c79d939ad54ca3a1d4e270b0b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 29 Jun 2010 22:55:45 -0700 Subject: uhd: work vectorizing the vrt packet handler, reworked vrt packet stuff, needs testing --- host/lib/transport/gen_vrt.py | 117 +++++++------- host/lib/transport/vrt_packet_handler.hpp | 252 ++++++++++++++++-------------- host/lib/types.cpp | 4 - host/lib/usrp/usrp2/io_impl.cpp | 32 ++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 9 +- 5 files changed, 219 insertions(+), 195 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 8e0fce9ff..ad87b9972 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -61,20 +61,22 @@ using namespace uhd::transport; #set $tsf_p = 0b01000 #set $tlr_p = 0b10000 -void vrt::pack_$(suffix)( - const tx_metadata_t &metadata, //input - boost::uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count, //input - double tick_rate //input +static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ + *(reinterpret_cast(mem)) = $(XE_MACRO)(num); +} + +void vrt::if_hdr_pack_$(suffix)( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ){ boost::uint32_t vrt_hdr_flags = 0; boost::uint8_t pred = 0; - if (metadata.has_stream_id) pred |= $hex($sid_p); - if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p); + if (if_packet_info.has_sid) pred |= $hex($sid_p); + if (if_packet_info.has_cid) pred |= $hex($cid_p); + if (if_packet_info.has_tsi) pred |= $hex($tsi_p); + if (if_packet_info.has_tsf) pred |= $hex($tsf_p); + if (if_packet_info.has_tlr) pred |= $hex($tlr_p); switch(pred){ #for $pred in range(2**5) @@ -83,79 +85,71 @@ void vrt::pack_$(suffix)( #set $flags = 0 ########## Stream ID ########## #if $pred & $sid_p - header_buff[$num_header_words] = $(XE_MACRO)(metadata.stream_id); + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); #set $num_header_words += 1 #set $flags |= (0x1 << 28); #end if ########## Class ID ########## #if $pred & $cid_p - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 + pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 #set $flags |= (0x1 << 27); #end if ########## Integer Time ########## #if $pred & $tsi_p - header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs())); + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); #set $num_header_words += 1 #set $flags |= (0x3 << 22); #end if ########## Fractional Time ########## #if $pred & $tsf_p - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 - header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate))); - #set $num_header_words += 1 + pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 #set $flags |= (0x1 << 20); #end if ########## Trailer ########## #if $pred & $tlr_p + packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); #set $flags |= (0x1 << 26); #set $num_trailer_words = 1; #else #set $num_trailer_words = 0; #end if ########## Variables ########## - num_header_words32 = $num_header_words; - num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32; + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; vrt_hdr_flags = $hex($flags); break; #end for } //set the burst flags - if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25); - if (metadata.end_of_burst) vrt_hdr_flags |= $hex(0x1 << 24); + if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); + if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); //fill in complete header word - header_buff[0] = $(XE_MACRO)(boost::uint32_t(0 + packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 | vrt_hdr_flags - | ((packet_count & 0xf) << 16) - | (num_packet_words32 & 0xffff) + | ((if_packet_info.packet_count & 0xf) << 16) + | (if_packet_info.num_packet_words32 & 0xffff) )); } -void vrt::unpack_$(suffix)( - rx_metadata_t &metadata, //output - const boost::uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count, //output - double tick_rate //input -){ - //clear the metadata - metadata = rx_metadata_t(); - boost::uint32_t secs = 0, ticks = 0; +static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ + num = $(XE_MACRO)(*reinterpret_cast(mem)); +} +void vrt::if_hdr_unpack_$(suffix)( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ //extract vrt header - boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]); + boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); size_t packet_words32 = vrt_hdr_word & 0xffff; - packet_count = (vrt_hdr_word >> 16) & 0xf; + if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0 or num_packet_words32 < packet_words32) + if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); @@ -174,41 +168,48 @@ void vrt::unpack_$(suffix)( #set $num_header_words = 1 ########## Stream ID ########## #if $pred & $sid_p - metadata.has_stream_id = true; - metadata.stream_id = $(XE_MACRO)(header_buff[$num_header_words]); + if_packet_info.has_sid = true; + if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); #set $num_header_words += 1 + #else + if_packet_info.has_sid = false; #end if ########## Class ID ########## #if $pred & $cid_p - #set $num_header_words += 1 - #set $num_header_words += 1 + if_packet_info.has_cid = true; + unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_cid = false; #end if ########## Integer Time ########## #if $pred & $tsi_p - #set $has_time_spec = True - secs = $(XE_MACRO)(header_buff[$num_header_words]); + if_packet_info.has_tsi = true; + if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); #set $num_header_words += 1 + #else + if_packet_info.has_tsi = false; #end if ########## Fractional Time ########## #if $pred & $tsf_p - #set $has_time_spec = True - #set $num_header_words += 1 - ticks = $(XE_MACRO)(header_buff[$num_header_words]); - #set $num_header_words += 1 - #end if - #if $has_time_spec - metadata.has_time_spec = true; - metadata.time_spec = time_spec_t(secs, ticks, tick_rate); + if_packet_info.has_tsf = true; + unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_tsf = false; #end if ########## Trailer ########## #if $pred & $tlr_p + if_packet_info.has_tlr = true; + if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); #set $num_trailer_words = 1; #else + if_packet_info.has_tlr = false; #set $num_trailer_words = 0; #end if ########## Variables ########## - num_header_words32 = $num_header_words; - num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); break; #end for } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 8dfc7b3d0..01cccd81e 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -30,37 +31,43 @@ #include #include #include +#include namespace vrt_packet_handler{ /*********************************************************************** * vrt packet handler for recv **********************************************************************/ + typedef std::vector managed_recv_buffs_t; + struct recv_state{ + //width of the receiver in channels + size_t width; + //init the expected seq number - size_t next_packet_seq; + std::vector next_packet_seq; //state variables to handle fragments - uhd::transport::managed_recv_buffer::sptr managed_buff; - boost::asio::const_buffer copy_buff; + managed_recv_buffs_t managed_buffs; + std::vector copy_buffs; + size_t size_of_copy_buffs; size_t fragment_offset_in_samps; - recv_state(void){ - //first expected seq is zero - next_packet_seq = 0; - - //initially empty copy buffer - copy_buff = boost::asio::buffer("", 0); + recv_state(size_t width): + width(width), + next_packet_seq(width, 0), + managed_buffs(width), + copy_buffs(width, NULL), + size_of_copy_buffs(0), + fragment_offset_in_samps(0) + { + /* NOP */ } }; - typedef boost::function get_recv_buff_t; - - typedef boost::function recv_cb_t; + typedef boost::function get_recv_buffs_t; - static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ - /* NOP */ - } + typedef boost::function recv_cb_t; /******************************************************************* * Unpack a received vrt header and set the copy buffer. @@ -74,33 +81,41 @@ namespace vrt_packet_handler{ vrt_unpacker_type vrt_unpacker, size_t vrt_header_offset_words32 ){ - size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + size_t num_packet_words32 = state.managed_buffs[0]->size()/sizeof(boost::uint32_t); if (num_packet_words32 <= vrt_header_offset_words32){ - state.copy_buff = boost::asio::buffer("", 0); + state.size_of_copy_buffs = 0; return; //must exit here after setting the buffer } - const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; - size_t num_header_words32_out, num_payload_words32_out, packet_count_out; - vrt_unpacker( - metadata, //output - vrt_hdr, //input - num_header_words32_out, //output - num_payload_words32_out, //output - num_packet_words32, //input - packet_count_out, //output - tick_rate - ); - //handle the packet count / sequence number - if (packet_count_out != state.next_packet_seq){ - std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + //vrt unpack each managed buffer + uhd::transport::vrt::if_packet_info_t if_packet_info; + for (size_t i = 0; i < state.width; i++){ + const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast() + vrt_header_offset_words32; + if_packet_info.num_packet_words32 = num_packet_words32; + vrt_unpacker(vrt_hdr, if_packet_info); + + //handle the packet count / sequence number + if (if_packet_info.packet_count != state.next_packet_seq[i]){ + std::cerr << "S" << (if_packet_info.packet_count - state.next_packet_seq[i])%16; + } + state.next_packet_seq[i] = (if_packet_info.packet_count+1)%16; + + //setup the buffer to point to the data + state.copy_buffs[i] = reinterpret_cast(vrt_hdr + if_packet_info.num_header_words32); + + //store the minimum payload length into the copy buffer length + size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t); + if (i == 0 or state.size_of_copy_buffs > num_payload_bytes){ + state.size_of_copy_buffs = num_payload_bytes; + } } - state.next_packet_seq = (packet_count_out+1)%16; - //setup the buffer to point to the data - state.copy_buff = boost::asio::buffer( - vrt_hdr + num_header_words32_out, - num_payload_words32_out*sizeof(boost::uint32_t) + //store the last vrt info into the metadata + metadata.has_time_spec = if_packet_info.has_tsi or if_packet_info.has_tsf; + metadata.time_spec = uhd::time_spec_t( + time_t((if_packet_info.has_tsi)? if_packet_info.tsi : 0), + size_t((if_packet_info.has_tsf)? if_packet_info.tsf : 0), + tick_rate ); } @@ -111,24 +126,22 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t _recv1( recv_state &state, - void *recv_mem, + const std::vector &buffs, + size_t offset_bytes, size_t total_samps, uhd::rx_metadata_t &metadata, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, vrt_unpacker_type vrt_unpacker, - const get_recv_buff_t &get_recv_buff, + const get_recv_buffs_t &get_recv_buffs, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32, - const recv_cb_t &recv_cb + size_t vrt_header_offset_words32 ){ //perform a receive if no rx data is waiting to be copied - if (boost::asio::buffer_size(state.copy_buff) == 0){ + if (state.size_of_copy_buffs == 0){ state.fragment_offset_in_samps = 0; - state.managed_buff = get_recv_buff(); - if (state.managed_buff.get() == NULL) return 0; - recv_cb(state.managed_buff); //callback before vrt unpack + if (not get_recv_buffs(state.managed_buffs)) return 0; try{ _recv1_helper( state, metadata, tick_rate, vrt_unpacker, vrt_header_offset_words32 @@ -141,26 +154,28 @@ namespace vrt_packet_handler{ //extract the number of samples available to copy size_t bytes_per_item = otw_type.get_sample_size(); - size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t bytes_available = state.size_of_copy_buffs; size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); + size_t bytes_to_copy = num_samps*bytes_per_item; //setup the fragment flags and offset metadata.more_fragments = total_samps < num_samps; metadata.fragment_offset = state.fragment_offset_in_samps; state.fragment_offset_in_samps += num_samps; //set for next call - //copy-convert the samples from the recv buffer - uhd::transport::convert_otw_type_to_io_type( - boost::asio::buffer_cast(state.copy_buff), otw_type, - recv_mem, io_type, num_samps - ); + for (size_t i = 0; i < state.width; i++){ + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + state.copy_buffs[i], otw_type, + reinterpret_cast(buffs[i]) + offset_bytes, + io_type, num_samps + ); - //update the rx copy buffer to reflect the bytes copied - size_t bytes_copied = num_samps*bytes_per_item; - state.copy_buff = boost::asio::buffer( - boost::asio::buffer_cast(state.copy_buff) + bytes_copied, - bytes_available - bytes_copied - ); + //update the rx copy buffer to reflect the bytes copied + state.copy_buffs[i] = reinterpret_cast(state.copy_buffs[i]) + bytes_to_copy; + } + //update the copy buffer's availability + state.size_of_copy_buffs -= bytes_to_copy; return num_samps; } @@ -171,20 +186,19 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t recv( recv_state &state, - const boost::asio::mutable_buffer &buff, + const std::vector &buffs, + const size_t total_num_samps, uhd::rx_metadata_t &metadata, uhd::device::recv_mode_t recv_mode, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, vrt_unpacker_type vrt_unpacker, - const get_recv_buff_t &get_recv_buff, + const get_recv_buffs_t &get_recv_buffs, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32 = 0, - const recv_cb_t& recv_cb = &recv_cb_nop + size_t vrt_header_offset_words32 = 0 ){ metadata = uhd::rx_metadata_t(); //init the metadata - const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; switch(recv_mode){ @@ -193,15 +207,14 @@ namespace vrt_packet_handler{ //////////////////////////////////////////////////////////////// return _recv1( state, - boost::asio::buffer_cast(buff), + buffs, 0, total_num_samps, metadata, io_type, otw_type, tick_rate, vrt_unpacker, - get_recv_buff, - vrt_header_offset_words32, - recv_cb + get_recv_buffs, + vrt_header_offset_words32 ); } @@ -213,15 +226,14 @@ namespace vrt_packet_handler{ while(accum_num_samps < total_num_samps){ size_t num_samps = _recv1( state, - boost::asio::buffer_cast(buff) + (accum_num_samps*io_type.size), + buffs, accum_num_samps*io_type.size, total_num_samps - accum_num_samps, (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept io_type, otw_type, tick_rate, vrt_unpacker, - get_recv_buff, - vrt_header_offset_words32, - recv_cb + get_recv_buffs, + vrt_header_offset_words32 ); if (num_samps == 0) break; //had a recv timeout or error, break loop accum_num_samps += num_samps; @@ -236,6 +248,8 @@ namespace vrt_packet_handler{ /*********************************************************************** * vrt packet handler for send **********************************************************************/ + typedef std::vector managed_send_buffs_t; + struct send_state{ //init the expected seq number size_t next_packet_seq; @@ -245,13 +259,9 @@ namespace vrt_packet_handler{ } }; - typedef boost::function get_send_buff_t; - - typedef boost::function send_cb_t; + typedef boost::function get_send_buffs_t; - static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ - /* NOP */ - } + typedef boost::function send_cb_t; /******************************************************************* * Pack a vrt header, copy-convert the data, and send it. @@ -260,46 +270,51 @@ namespace vrt_packet_handler{ template static UHD_INLINE void _send1( send_state &state, - const void *send_mem, + const std::vector &buffs, + size_t offset_bytes, size_t num_samps, const uhd::tx_metadata_t &metadata, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, vrt_packer_type vrt_packer, - const get_send_buff_t &get_send_buff, - size_t vrt_header_offset_words32, - const send_cb_t& send_cb + const get_send_buffs_t &get_send_buffs, + size_t vrt_header_offset_words32 ){ - //get a new managed send buffer - uhd::transport::managed_send_buffer::sptr send_buff = get_send_buff(); - boost::uint32_t *tx_mem = send_buff->cast() + vrt_header_offset_words32; - - size_t num_header_words32, num_packet_words32; - size_t packet_count = state.next_packet_seq++; - - //pack metadata into a vrt header - vrt_packer( - metadata, //input - tx_mem, //output - num_header_words32, //output - num_samps, //input - num_packet_words32, //output - packet_count, //input - tick_rate - ); - - //copy-convert the samples into the send buffer - uhd::transport::convert_io_type_to_otw_type( - send_mem, io_type, - tx_mem + num_header_words32, otw_type, - num_samps - ); - - send_cb(send_buff); //callback after memory filled + //translate the metadata to vrt if packet info + uhd::transport::vrt::if_packet_info_t if_packet_info; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = metadata.has_time_spec; + if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); + if_packet_info.has_tsf = metadata.has_time_spec; + if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); + if_packet_info.has_tlr = false; + if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); + if_packet_info.packet_count = state.next_packet_seq++; + + //get send buffers for each channel + managed_send_buffs_t send_buffs(buffs.size()); + UHD_ASSERT_THROW(get_send_buffs(send_buffs)); + + for (size_t i = 0; i < buffs.size(); i++){ + //calculate pointers with offsets to io and otw memory + const boost::uint8_t *io_mem = reinterpret_cast(buffs[i]) + offset_bytes; + boost::uint32_t *otw_mem = send_buffs[i]->cast() + vrt_header_offset_words32; + + //pack metadata into a vrt header + vrt_packer(otw_mem, if_packet_info); + + //copy-convert the samples into the send buffer + uhd::transport::convert_io_type_to_otw_type( + io_mem, io_type, + otw_mem + if_packet_info.num_header_words32, otw_type, + num_samps + ); - //commit the samples to the zero-copy interface - send_buff->commit(num_packet_words32*sizeof(boost::uint32_t)); + //commit the samples to the zero-copy interface + send_buffs[i]->commit(if_packet_info.num_packet_words32*sizeof(boost::uint32_t)); + } } /******************************************************************* @@ -308,20 +323,19 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t send( send_state &state, - const boost::asio::const_buffer &buff, + const std::vector &buffs, + const size_t total_num_samps, const uhd::tx_metadata_t &metadata, uhd::device::send_mode_t send_mode, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, vrt_packer_type vrt_packer, - const get_send_buff_t &get_send_buff, + const get_send_buffs_t &get_send_buffs, size_t max_samples_per_packet, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32 = 0, - const send_cb_t& send_cb = &send_cb_nop + size_t vrt_header_offset_words32 = 0 ){ - const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ @@ -331,15 +345,14 @@ namespace vrt_packet_handler{ size_t num_samps = std::min(total_num_samps, max_samples_per_packet); _send1( state, - boost::asio::buffer_cast(buff), + buffs, 0, num_samps, metadata, io_type, otw_type, tick_rate, vrt_packer, - get_send_buff, - vrt_header_offset_words32, - send_cb + get_send_buffs, + vrt_header_offset_words32 ); return num_samps; } @@ -366,15 +379,14 @@ namespace vrt_packet_handler{ //send the fragment with the helper function _send1( state, - boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + buffs, n*max_samples_per_packet*io_type.size, (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, md, io_type, otw_type, tick_rate, vrt_packer, - get_send_buff, - vrt_header_offset_words32, - send_cb + get_send_buffs, + vrt_header_offset_words32 ); } return total_num_samps; diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 6a9fcf5b5..9cf2a2220 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -96,8 +96,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): * metadata **********************************************************************/ rx_metadata_t::rx_metadata_t(void): - has_stream_id(false), - stream_id(0), has_time_spec(false), time_spec(time_spec_t()), more_fragments(false), @@ -107,8 +105,6 @@ rx_metadata_t::rx_metadata_t(void): } tx_metadata_t::tx_metadata_t(void): - has_stream_id(false), - stream_id(0), has_time_spec(false), time_spec(time_spec_t()), start_of_burst(false), diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index aa0f63321..e3a3a3b17 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -52,7 +52,7 @@ struct usrp2_impl::io_impl{ bounded_buffer::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if){ +usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if): packet_handler_recv_state(1){ //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; @@ -130,19 +130,26 @@ void usrp2_impl::io_init(void){ /*********************************************************************** * Send Data **********************************************************************/ +bool tmp_todo_fixme_remove_get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs, const zero_copy_if::sptr &zc_if){ + buffs[0] = zc_if->get_send_buff(); + return buffs[0].get() != NULL; +} + size_t usrp2_impl::send( - const asio::const_buffer &buff, + const std::vector &buffs, + size_t nsamps_per_buff, 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 + buffs, nsamps_per_buff, //buffer to empty + metadata, send_mode, //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), + uhd::transport::vrt::if_hdr_pack_be, + boost::bind(&tmp_todo_fixme_remove_get_send_buffs, _1, _data_transport), get_max_send_samps_per_packet() ); } @@ -150,18 +157,25 @@ size_t usrp2_impl::send( /*********************************************************************** * Receive Data **********************************************************************/ +bool tmp_todo_fixme_remove_get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, boost::shared_ptr impl){ + buffs[0] = impl->get_recv_buff(); + return buffs[0].get() != NULL; +} + size_t usrp2_impl::recv( - const asio::mutable_buffer &buff, + const std::vector &buffs, + size_t nsamps_per_buff, 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 + buffs, nsamps_per_buff, //buffer to empty + metadata, recv_mode, //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) + uhd::transport::vrt::if_hdr_unpack_be, + boost::bind(&tmp_todo_fixme_remove_get_recv_buffs, _1, _io_impl) ); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2126b9565..70735173e 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -108,7 +108,7 @@ public: return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); } size_t send( - const boost::asio::const_buffer &, + const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t @@ -117,12 +117,14 @@ public: return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t recv( - const boost::asio::mutable_buffer &, + const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, uhd::device::recv_mode_t ); + UHD_PIMPL_DECL(io_impl) _io_impl; + private: inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); @@ -148,11 +150,10 @@ private: ; static const size_t _max_tx_bytes_per_packet = USRP2_UDP_BYTES - - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) ; uhd::otw_type_t _rx_otw_type, _tx_otw_type; - UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); //udp transports for control and data -- cgit v1.2.3 From 9183ca62eb8fba96cf527d3cefa0a48f67397a57 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 11:13:24 -0700 Subject: uhd: forgot burst flags, tweaks to vrt info -> metadata --- host/lib/transport/gen_vrt.py | 3 ++- host/lib/transport/vrt_packet_handler.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index ad87b9972..06182bd39 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -109,10 +109,11 @@ void vrt::if_hdr_pack_$(suffix)( #end if ########## Trailer ########## #if $pred & $tlr_p - packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); #set $flags |= (0x1 << 26); #set $num_trailer_words = 1; #else + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; #set $num_trailer_words = 0; #end if ########## Variables ########## diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 01cccd81e..63bf95204 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -111,11 +111,9 @@ namespace vrt_packet_handler{ } //store the last vrt info into the metadata - metadata.has_time_spec = if_packet_info.has_tsi or if_packet_info.has_tsf; + metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; metadata.time_spec = uhd::time_spec_t( - time_t((if_packet_info.has_tsi)? if_packet_info.tsi : 0), - size_t((if_packet_info.has_tsf)? if_packet_info.tsf : 0), - tick_rate + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate ); } @@ -292,6 +290,8 @@ namespace vrt_packet_handler{ if_packet_info.has_tlr = false; if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq++; + if_packet_info.sob = metadata.start_of_burst; + if_packet_info.eob = metadata.end_of_burst; //get send buffers for each channel managed_send_buffs_t send_buffs(buffs.size()); -- cgit v1.2.3 From a38a0943490d10da733a529156a7650c056028e6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 12:08:45 -0700 Subject: uhd: vrt packet handler fix and tweaks --- host/lib/transport/vrt_packet_handler.hpp | 66 ++++++++++++++----------------- 1 file changed, 30 insertions(+), 36 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 63bf95204..8cbc71008 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -39,6 +39,7 @@ namespace vrt_packet_handler{ * vrt packet handler for recv **********************************************************************/ typedef std::vector managed_recv_buffs_t; + typedef boost::function get_recv_buffs_t; struct recv_state{ //width of the receiver in channels @@ -65,10 +66,6 @@ namespace vrt_packet_handler{ } }; - typedef boost::function get_recv_buffs_t; - - typedef boost::function recv_cb_t; - /******************************************************************* * Unpack a received vrt header and set the copy buffer. * - helper function for vrt_packet_handler::_recv1 @@ -136,6 +133,8 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 ){ + metadata.has_time_spec = false; //false unless set in the helper + //perform a receive if no rx data is waiting to be copied if (state.size_of_copy_buffs == 0){ state.fragment_offset_in_samps = 0; @@ -196,8 +195,6 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0 ){ - metadata = uhd::rx_metadata_t(); //init the metadata - switch(recv_mode){ //////////////////////////////////////////////////////////////// @@ -247,20 +244,17 @@ namespace vrt_packet_handler{ * vrt packet handler for send **********************************************************************/ typedef std::vector managed_send_buffs_t; + typedef boost::function get_send_buffs_t; struct send_state{ //init the expected seq number size_t next_packet_seq; - send_state(void){ - next_packet_seq = 0; + send_state(void) : next_packet_seq(0){ + /* NOP */ } }; - typedef boost::function get_send_buffs_t; - - typedef boost::function send_cb_t; - /******************************************************************* * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send @@ -271,27 +265,16 @@ namespace vrt_packet_handler{ const std::vector &buffs, size_t offset_bytes, size_t num_samps, - const uhd::tx_metadata_t &metadata, + uhd::transport::vrt::if_packet_info_t &if_packet_info, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, - double tick_rate, vrt_packer_type vrt_packer, const get_send_buffs_t &get_send_buffs, size_t vrt_header_offset_words32 ){ - //translate the metadata to vrt if packet info - uhd::transport::vrt::if_packet_info_t if_packet_info; - if_packet_info.has_sid = false; - if_packet_info.has_cid = false; - if_packet_info.has_tsi = metadata.has_time_spec; - if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); - if_packet_info.has_tsf = metadata.has_time_spec; - if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); - if_packet_info.has_tlr = false; - if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); + //load the rest of the if_packet_info in here + if_packet_info.num_payload_words32 = (num_samps*otw_type.get_sample_size())/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq++; - if_packet_info.sob = metadata.start_of_burst; - if_packet_info.eob = metadata.end_of_burst; //get send buffers for each channel managed_send_buffs_t send_buffs(buffs.size()); @@ -336,6 +319,14 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0 ){ + //translate the metadata to vrt if packet info + uhd::transport::vrt::if_packet_info_t if_packet_info; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tlr = false; + if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); + if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); + if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ @@ -343,13 +334,19 @@ namespace vrt_packet_handler{ case uhd::device::SEND_MODE_ONE_PACKET:{ //////////////////////////////////////////////////////////////// size_t num_samps = std::min(total_num_samps, max_samples_per_packet); + + //fill in parts of the packet info overwrote in full buff mode + if_packet_info.has_tsi = metadata.has_time_spec; + if_packet_info.has_tsf = metadata.has_time_spec; + if_packet_info.sob = metadata.start_of_burst; + if_packet_info.eob = metadata.end_of_burst; + _send1( state, buffs, 0, num_samps, - metadata, + if_packet_info, io_type, otw_type, - tick_rate, vrt_packer, get_send_buffs, vrt_header_offset_words32 @@ -365,25 +362,22 @@ namespace vrt_packet_handler{ static const size_t first_fragment_index = 0; const size_t final_fragment_index = num_fragments-1; - //make a rw copy of the metadata to re-flag below - uhd::tx_metadata_t md(metadata); - //loop through the following fragment indexes for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ //calculate new flags for the fragments - md.has_time_spec = metadata.has_time_spec and (n == first_fragment_index); - md.start_of_burst = metadata.start_of_burst and (n == first_fragment_index); - md.end_of_burst = metadata.end_of_burst and (n == final_fragment_index); + if_packet_info.has_tsi = metadata.has_time_spec and (n == first_fragment_index); + if_packet_info.has_tsf = metadata.has_time_spec and (n == first_fragment_index); + if_packet_info.sob = metadata.start_of_burst and (n == first_fragment_index); + if_packet_info.eob = metadata.end_of_burst and (n == final_fragment_index); //send the fragment with the helper function _send1( state, buffs, n*max_samples_per_packet*io_type.size, (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, - md, + if_packet_info, io_type, otw_type, - tick_rate, vrt_packer, get_send_buffs, vrt_header_offset_words32 -- cgit v1.2.3 From 905f5b3b249a60401e181856ac6b3f2cae88d166 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 16:21:46 -0700 Subject: usrp2: split mboard impl into its own class, usrp2 device can instantiate N mboard impls for mimo setup (works with 1 for now) --- host/lib/usrp/usrp2/dboard_impl.cpp | 18 ++-- host/lib/usrp/usrp2/dsp_impl.cpp | 20 ++--- host/lib/usrp/usrp2/io_impl.cpp | 113 ++++++++++++----------- host/lib/usrp/usrp2/mboard_impl.cpp | 78 +++++++++++++--- host/lib/usrp/usrp2/usrp2_impl.cpp | 102 ++++++++++----------- host/lib/usrp/usrp2/usrp2_impl.hpp | 175 +++++++++++++++++++----------------- 6 files changed, 282 insertions(+), 224 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index fef486771..fa8d1a674 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -33,7 +33,7 @@ using namespace uhd::usrp; /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_impl::dboard_init(void){ +void usrp2_mboard_impl::dboard_init(void){ //read the dboard eeprom to extract the dboard ids _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); @@ -46,12 +46,12 @@ void usrp2_impl::dboard_init(void){ //load dboards _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2) ); _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2) ); //init the subdevs in use (use the first subdevice) @@ -62,7 +62,7 @@ void usrp2_impl::dboard_init(void){ /*********************************************************************** * RX DBoard Properties **********************************************************************/ -void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -96,7 +96,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DBOARD_PROP_USED_SUBDEVS:{ _rx_subdevs_in_use = val.as(); @@ -122,7 +122,7 @@ void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * TX DBoard Properties **********************************************************************/ -void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -156,7 +156,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DBOARD_PROP_USED_SUBDEVS:{ _tx_subdevs_in_use = val.as(); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 367cde2e1..c315a2eec 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -41,11 +41,11 @@ pick_closest_rate(double exact_rate, const std::vector &rates){ return closest_match; } -void usrp2_impl::init_ddc_config(void){ +void usrp2_mboard_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict _rx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::ddc_get, this, _1, _2), - boost::bind(&usrp2_impl::ddc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2) ); //initial config and update @@ -56,7 +56,7 @@ void usrp2_impl::init_ddc_config(void){ /*********************************************************************** * DDC Properties **********************************************************************/ -void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); @@ -82,7 +82,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ @@ -116,11 +116,11 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * DUC Helper Methods **********************************************************************/ -void usrp2_impl::init_duc_config(void){ +void usrp2_mboard_impl::init_duc_config(void){ //create the duc in the tx dsp dict _tx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::duc_get, this, _1, _2), - boost::bind(&usrp2_impl::duc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2) ); //initial config and update @@ -131,7 +131,7 @@ void usrp2_impl::init_duc_config(void){ /*********************************************************************** * DUC Properties **********************************************************************/ -void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); @@ -157,7 +157,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index e3a3a3b17..8b1864e2d 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 #include -#include +#include #include #include //htonl and ntohl #include @@ -36,54 +36,58 @@ namespace asio = boost::asio; * io impl details (internal to this file) **********************************************************************/ struct usrp2_impl::io_impl{ + typedef alignment_buffer alignment_buffer_type; - io_impl(zero_copy_if::sptr zc_if); + io_impl(std::vector &zc_ifs); ~io_impl(void); - managed_recv_buffer::sptr get_recv_buff(void); + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs); //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::sptr recv_pirate_booty; + void recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index); + boost::thread_group recv_pirate_crew; + bool recv_pirate_crew_running; + alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if): packet_handler_recv_state(1){ +usrp2_impl::io_impl::io_impl(std::vector &zc_ifs): + packet_handler_recv_state(zc_ifs.size()) +{ //create a large enough booty - size_t num_frames = zc_if->get_num_recv_frames(); + size_t num_frames = zc_ifs.at(0)->get_num_recv_frames(); std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = bounded_buffer::make(num_frames); + recv_pirate_booty = alignment_buffer_type::make(num_frames, zc_ifs.size()); - //create a new pirate thread (yarr!!) - recv_pirate_thread = new boost::thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_if) - ); + //create a new pirate thread for each zc if (yarr!!) + for (size_t i = 0; i < zc_ifs.size(); i++){ + recv_pirate_crew.create_thread( + boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_ifs.at(i), i) + ); + } } usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_running = false; - recv_pirate_thread->interrupt(); - recv_pirate_thread->join(); - delete recv_pirate_thread; + recv_pirate_crew_running = false; + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); } -managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){ - managed_recv_buffer::sptr buff; +bool usrp2_impl::io_impl::get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ 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... + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); } -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ +void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index){ set_thread_priority_safe(); - recv_pirate_running = true; - while(recv_pirate_running){ + recv_pirate_crew_running = true; + while(recv_pirate_crew_running){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff); + //TODO unpack vrt, get time spec, round to nearest packet bound, use below: + if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff, time_spec_t(/*todoseq*/), index); } } @@ -102,54 +106,54 @@ void usrp2_impl::io_init(void){ _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; //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(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); + 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(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); + } - //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); + //setup VRT RX DSP regs + for(size_t i = 0; i < _mboards.size(); i++){ + _mboards[i]->setup_vrt_recv_regs(get_max_recv_samps_per_packet()); + } + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; 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)); + _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transports)); } /*********************************************************************** * Send Data **********************************************************************/ -bool tmp_todo_fixme_remove_get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs, const zero_copy_if::sptr &zc_if){ - buffs[0] = zc_if->get_send_buff(); - return buffs[0].get() != NULL; +bool get_send_buffs( + const std::vector &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 std::vector &buffs, - size_t nsamps_per_buff, + 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 - buffs, nsamps_per_buff, //buffer to empty + buffs, num_samps, //buffer to fill metadata, send_mode, //samples metadata io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_pack_be, - boost::bind(&tmp_todo_fixme_remove_get_send_buffs, _1, _data_transport), + boost::bind(&get_send_buffs, _data_transports, _1), get_max_send_samps_per_packet() ); } @@ -157,25 +161,20 @@ size_t usrp2_impl::send( /*********************************************************************** * Receive Data **********************************************************************/ -bool tmp_todo_fixme_remove_get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, boost::shared_ptr impl){ - buffs[0] = impl->get_recv_buff(); - return buffs[0].get() != NULL; -} - size_t usrp2_impl::recv( const std::vector &buffs, - size_t nsamps_per_buff, + 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 - buffs, nsamps_per_buff, //buffer to empty + buffs, num_samps, //buffer to fill metadata, recv_mode, //samples metadata io_type, _rx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, - boost::bind(&tmp_todo_fixme_remove_get_recv_buffs, _1, _io_impl) + boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl, _1) ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 2c900b328..903d5da86 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -29,17 +29,71 @@ using namespace uhd; using namespace uhd::usrp; +/*********************************************************************** + * Structors + **********************************************************************/ +usrp2_mboard_impl::usrp2_mboard_impl( + size_t index, transport::udp_simple::sptr ctrl_transport +): + _index(index) +{ + //make a new interface for usrp2 stuff + _iface = usrp2_iface::make(ctrl_transport); + _clock_ctrl = usrp2_clock_ctrl::make(_iface); + _codec_ctrl = usrp2_codec_ctrl::make(_iface); + _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); + + //TODO move to dsp impl... + //load the allowed decim/interp rates + //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) + _allowed_decim_and_interp_rates.clear(); + for (size_t i = 4; i <= 128; i+=1){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 130; i <= 256; i+=2){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 260; i <= 512; i+=4){ + _allowed_decim_and_interp_rates.push_back(i); + } + + //init the ddc + init_ddc_config(); + + //init the duc + init_duc_config(); + + //initialize the clock configuration + init_clock_config(); + + //init the tx and rx dboards (do last) + dboard_init(); +} + +usrp2_mboard_impl::~usrp2_mboard_impl(void){ + /* NOP */ +} + /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_impl::mboard_init(void){ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::mboard_get, this, _1, _2), - boost::bind(&usrp2_impl::mboard_set, this, _1, _2) +void usrp2_mboard_impl::setup_vrt_recv_regs(size_t num_samps){ + _max_recv_samps_per_packet = num_samps; + + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _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); } -void usrp2_impl::init_clock_config(void){ +void usrp2_mboard_impl::init_clock_config(void){ //setup the clock configuration settings _clock_config.ref_source = clock_config_t::REF_INT; _clock_config.pps_source = clock_config_t::PPS_SMA; @@ -49,7 +103,7 @@ void usrp2_impl::init_clock_config(void){ update_clock_config(); } -void usrp2_impl::update_clock_config(void){ +void usrp2_mboard_impl::update_clock_config(void){ boost::uint32_t pps_flags = 0; //translate pps source enums @@ -82,7 +136,7 @@ void usrp2_impl::update_clock_config(void){ _clock_ctrl->enable_external_ref(use_external); } -void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ +void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set the ticks _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); @@ -94,7 +148,7 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); } -void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ +void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ UHD_ASSERT_THROW(stream_cmd.num_samps <= U2_REG_RX_CTRL_MAX_SAMPS_PER_CMD); //setup the mode to instruction flags @@ -113,7 +167,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, U2_REG_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_recv_samps_per_packet : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 @@ -125,7 +179,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ /*********************************************************************** * MBoard Get Properties **********************************************************************/ -void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -148,7 +202,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ case MBOARD_PROP_NAME: - val = std::string("usrp2 mboard"); + val = str(boost::format("usrp2 mboard %d") % _index); return; case MBOARD_PROP_OTHERS:{ @@ -207,7 +261,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ /*********************************************************************** * MBoard Set Properties **********************************************************************/ -void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 36c264c3c..af496bf69 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,15 @@ UHD_STATIC_BLOCK(register_usrp2_device){ device::register_device(&usrp2::find, &usrp2::make); } +/*********************************************************************** + * Helper Functions + **********************************************************************/ +std::vector split_addrs(const std::string &addrs_str){ + std::vector addrs; + boost::split(addrs, addrs_str, boost::is_any_of("\t ")); + return addrs; +} + /*********************************************************************** * Discovery over the udp transport **********************************************************************/ @@ -66,6 +76,16 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ return usrp2_addrs; } + //if there are multiple addresses, just return good, dont test + std::vector addrs = split_addrs(hint["addr"]); + if (addrs.size() > 1){ + device_addr_t new_addr; + new_addr["type"] = "usrp2"; + new_addr["addr"] = hint["addr"]; + usrp2_addrs.push_back(new_addr); + return usrp2_addrs; + } + //create a udp transport to communicate std::string ctrl_port = boost::lexical_cast(USRP2_UDP_CTRL_PORT); udp_simple::sptr udp_transport = udp_simple::make_broadcast( @@ -112,11 +132,6 @@ template std::string num2str(T num){ } device::sptr usrp2::make(const device_addr_t &device_addr){ - //create a control transport - udp_simple::sptr ctrl_transport = udp_simple::make_connected( - device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) - ); - //extract the receive and send buffer sizes size_t recv_buff_size = 0, send_buff_size= 0 ; if (device_addr.has_key("recv_buff_size")){ @@ -126,17 +141,23 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ send_buff_size = size_t(boost::lexical_cast(device_addr["send_buff_size"])); } - //create a data transport - udp_zero_copy::sptr data_transport = udp_zero_copy::make( - device_addr["addr"], - num2str(USRP2_UDP_DATA_PORT), - recv_buff_size, - send_buff_size - ); + //create a ctrl and data transport for each address + std::vector ctrl_transports; + std::vector data_transports; + + BOOST_FOREACH(const std::string &addr, split_addrs(device_addr["addr"])){ + ctrl_transports.push_back(udp_simple::make_connected( + addr, num2str(USRP2_UDP_CTRL_PORT) + )); + data_transports.push_back(udp_zero_copy::make( + addr, num2str(USRP2_UDP_DATA_PORT), + recv_buff_size, send_buff_size + )); + } //create the usrp2 implementation guts return device::sptr( - new usrp2_impl(ctrl_transport, data_transport) + new usrp2_impl(ctrl_transports, data_transports) ); } @@ -144,44 +165,20 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - udp_simple::sptr ctrl_transport, - udp_zero_copy::sptr data_transport -){ - _data_transport = data_transport; - - //make a new interface for usrp2 stuff - _iface = usrp2_iface::make(ctrl_transport); - _clock_ctrl = usrp2_clock_ctrl::make(_iface); - _codec_ctrl = usrp2_codec_ctrl::make(_iface); - _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); - - //load the allowed decim/interp rates - //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) - _allowed_decim_and_interp_rates.clear(); - for (size_t i = 4; i <= 128; i+=1){ - _allowed_decim_and_interp_rates.push_back(i); - } - for (size_t i = 130; i <= 256; i+=2){ - _allowed_decim_and_interp_rates.push_back(i); + std::vector ctrl_transports, + std::vector data_transports +): + _data_transports(data_transports) +{ + //create a new mboard handler for each control transport + for(size_t i = 0; i < ctrl_transports.size(); i++){ + _mboards.push_back(usrp2_mboard_impl::sptr( + new usrp2_mboard_impl(i, ctrl_transports[i]) + )); + //use an empty name when there is only one mboard + std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast(i) : ""; + _mboard_dict[name] = _mboards.back(); } - for (size_t i = 260; i <= 512; i+=4){ - _allowed_decim_and_interp_rates.push_back(i); - } - - //init the mboard - mboard_init(); - - //init the ddc - init_ddc_config(); - - //init the duc - init_duc_config(); - - //initialize the clock configuration - init_clock_config(); - - //init the tx and rx dboards (do last) - dboard_init(); //init the send and recv io io_init(); @@ -206,12 +203,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(name == ""); - val = _mboard_proxy->get_link(); + val = _mboard_dict[name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); + val = prop_names_t(_mboard_dict.keys()); return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 70735173e..ccda5e3d8 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -62,102 +62,50 @@ public: return sptr(new wax_obj_proxy(get, set)); } - ~wax_obj_proxy(void){ - /* NOP */ - } - private: - get_t _get; - set_t _set; - - wax_obj_proxy(const get_t &get, const set_t &set){ - _get = get; - _set = set; - }; - - void get(const wax::obj &key, wax::obj &val){ - return _get(key, val); - } - - void set(const wax::obj &key, const wax::obj &val){ - return _set(key, val); - } + get_t _get; set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; + void get(const wax::obj &key, wax::obj &val){return _get(key, val);} + void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; /*! - * USRP2 implementation guts: + * USRP2 mboard implementation guts: * The implementation details are encapsulated here. * Handles properties on the mboard, dboard, dsps... */ -class usrp2_impl : public uhd::device{ +class usrp2_mboard_impl : public wax::obj{ public: - /*! - * Create a new usrp2 impl base. - * \param ctrl_transport the udp transport for control - * \param data_transport the udp transport for data - */ - usrp2_impl( - uhd::transport::udp_simple::sptr ctrl_transport, - uhd::transport::udp_zero_copy::sptr data_transport - ); + typedef boost::shared_ptr sptr; - ~usrp2_impl(void); + //structors + usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr); + ~usrp2_mboard_impl(void); - //the io interface - size_t get_max_send_samps_per_packet(void) const{ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); - } - size_t send( - const std::vector &, size_t, - const uhd::tx_metadata_t &, - const uhd::io_type_t &, - uhd::device::send_mode_t - ); - size_t get_max_recv_samps_per_packet(void) const{ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); - } - size_t recv( - const std::vector &, size_t, - uhd::rx_metadata_t &, - const uhd::io_type_t &, - uhd::device::recv_mode_t - ); - - UHD_PIMPL_DECL(io_impl) _io_impl; + void setup_vrt_recv_regs(size_t num_samps); -private: inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); } - //device properties interface + //properties for this mboard void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); +private: + size_t _index; + size_t _max_recv_samps_per_packet; + //interfaces usrp2_iface::sptr _iface; usrp2_clock_ctrl::sptr _clock_ctrl; usrp2_codec_ctrl::sptr _codec_ctrl; usrp2_serdes_ctrl::sptr _serdes_ctrl; - /******************************************************************* - * Deal with the rx and tx packet sizes - ******************************************************************/ - static const size_t _max_rx_bytes_per_packet = - USRP2_UDP_BYTES - - USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - - USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) - ; - static const size_t _max_tx_bytes_per_packet = - USRP2_UDP_BYTES - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - ; - - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - void io_init(void); - - //udp transports for control and data - uhd::transport::udp_zero_copy::sptr _data_transport; + //rx and tx dboard methods and objects + uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; + void dboard_init(void); //methods and shadows for clock configuration uhd::clock_config_t _clock_config; @@ -165,17 +113,6 @@ private: void update_clock_config(void); void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - //rx and tx dboard methods and objects - uhd::usrp::dboard_manager::sptr _dboard_manager; - uhd::usrp::dboard_iface::sptr _dboard_iface; - void dboard_init(void); - - //properties for the mboard - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - //properties interface for rx dboard void rx_dboard_get(const wax::obj &, wax::obj &); void rx_dboard_set(const wax::obj &, const wax::obj &); @@ -214,4 +151,76 @@ private: }; +/*! + * USRP2 implementation guts: + * The implementation details are encapsulated here. + * Handles device properties and streaming... + */ +class usrp2_impl : public uhd::device{ +public: + /*! + * Create a new usrp2 impl base. + * \param ctrl_transports the udp transports for control + * \param data_transports the udp transports for data + */ + usrp2_impl( + std::vector ctrl_transports, + std::vector data_transports + ); + + ~usrp2_impl(void); + + //the io interface + size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } + size_t send( + const std::vector &, size_t, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + uhd::device::send_mode_t + ); + size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } + size_t recv( + const std::vector &, size_t, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); + +private: + inline double get_master_clock_freq(void){ + return _mboards.front()->get_master_clock_freq(); + } + + //device properties interface + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //pointers to mboards on this device (think mimo setup) + std::vector _mboards; + uhd::dict _mboard_dict; + + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ + static const size_t _max_rx_bytes_per_packet = + USRP2_UDP_BYTES - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) + ; + static const size_t _max_tx_bytes_per_packet = + USRP2_UDP_BYTES - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + ; + + std::vector _data_transports; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); +}; + #endif /* INCLUDED_USRP2_IMPL_HPP */ -- cgit v1.2.3 From 158bf440d2884b981a86121990be16decedaa733 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 17:34:35 -0700 Subject: usrp2: moved calculations for max packet size and otw types into shared object between device and mboards --- host/lib/usrp/usrp2/io_impl.cpp | 35 +++++---------- host/lib/usrp/usrp2/mboard_impl.cpp | 38 ++++++++-------- host/lib/usrp/usrp2/usrp2_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 86 +++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 73 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 8b1864e2d..0c92c33b2 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -95,16 +95,6 @@ void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t inde * 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; - - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_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(); @@ -113,11 +103,6 @@ void usrp2_impl::io_init(void){ send_buff->commit(sizeof(data)); } - //setup VRT RX DSP regs - for(size_t i = 0; i < _mboards.size(); i++){ - _mboards[i]->setup_vrt_recv_regs(get_max_recv_samps_per_packet()); - } - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; @@ -147,11 +132,11 @@ size_t usrp2_impl::send( send_mode_t send_mode ){ return vrt_packet_handler::send( - _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, _tx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate + _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() @@ -169,11 +154,11 @@ size_t usrp2_impl::recv( recv_mode_t recv_mode ){ return vrt_packet_handler::recv( - _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, _rx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate + _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) ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 903d5da86..28a346be7 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -33,9 +33,12 @@ using namespace uhd::usrp; * Structors **********************************************************************/ usrp2_mboard_impl::usrp2_mboard_impl( - size_t index, transport::udp_simple::sptr ctrl_transport + size_t index, + transport::udp_simple::sptr ctrl_transport, + const usrp2_io_helper &io_helper ): - _index(index) + _index(index), + _io_helper(io_helper) { //make a new interface for usrp2 stuff _iface = usrp2_iface::make(ctrl_transport); @@ -57,6 +60,19 @@ usrp2_mboard_impl::usrp2_mboard_impl( _allowed_decim_and_interp_rates.push_back(i); } + //setup the vrt rx registers + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.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); + //init the ddc init_ddc_config(); @@ -77,22 +93,6 @@ usrp2_mboard_impl::~usrp2_mboard_impl(void){ /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_mboard_impl::setup_vrt_recv_regs(size_t num_samps){ - _max_recv_samps_per_packet = num_samps; - - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _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); -} - void usrp2_mboard_impl::init_clock_config(void){ //setup the clock configuration settings _clock_config.ref_source = clock_config_t::REF_INT; @@ -167,7 +167,7 @@ void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, U2_REG_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_recv_samps_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _io_helper.get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index af496bf69..436146a48 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -173,7 +173,7 @@ usrp2_impl::usrp2_impl( //create a new mboard handler for each control transport for(size_t i = 0; i < ctrl_transports.size(); i++){ _mboards.push_back(usrp2_mboard_impl::sptr( - new usrp2_mboard_impl(i, ctrl_transports[i]) + new usrp2_mboard_impl(i, ctrl_transports[i], _io_helper) )); //use an empty name when there is only one mboard std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ccda5e3d8..719cf3f16 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -69,6 +69,55 @@ private: void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; +/*! + * The io helper class encapculates the max packet sizes and otw types. + * The otw types are read-only for now, this will be reimplemented + * when it becomes possible to change the otw type in the usrp2. + */ +class usrp2_io_helper{ +public: + usrp2_io_helper(void){ + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + } + + inline size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } + + inline size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } + + inline const uhd::otw_type_t &get_rx_otw_type(void) const{ + return _rx_otw_type; + } + + inline const uhd::otw_type_t &get_tx_otw_type(void) const{ + return _tx_otw_type; + } + +private: + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + static const size_t _max_rx_bytes_per_packet = + USRP2_UDP_BYTES - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) + ; + static const size_t _max_tx_bytes_per_packet = + USRP2_UDP_BYTES - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + ; +}; + /*! * USRP2 mboard implementation guts: * The implementation details are encapsulated here. @@ -79,23 +128,21 @@ public: typedef boost::shared_ptr sptr; //structors - usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr); + usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr, const usrp2_io_helper &); ~usrp2_mboard_impl(void); - void setup_vrt_recv_regs(size_t num_samps); - inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); } +private: + size_t _index; + const usrp2_io_helper &_io_helper; + //properties for this mboard void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); -private: - size_t _index; - size_t _max_recv_samps_per_packet; - //interfaces usrp2_iface::sptr _iface; usrp2_clock_ctrl::sptr _clock_ctrl; @@ -172,7 +219,7 @@ public: //the io interface size_t get_max_send_samps_per_packet(void) const{ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + return _io_helper.get_max_send_samps_per_packet(); } size_t send( const std::vector &, size_t, @@ -181,7 +228,7 @@ public: uhd::device::send_mode_t ); size_t get_max_recv_samps_per_packet(void) const{ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + return _io_helper.get_max_recv_samps_per_packet(); } size_t recv( const std::vector &, size_t, @@ -191,10 +238,6 @@ public: ); private: - inline double get_master_clock_freq(void){ - return _mboards.front()->get_master_clock_freq(); - } - //device properties interface void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); @@ -203,22 +246,9 @@ private: std::vector _mboards; uhd::dict _mboard_dict; - /******************************************************************* - * Deal with the rx and tx packet sizes - ******************************************************************/ - static const size_t _max_rx_bytes_per_packet = - USRP2_UDP_BYTES - - USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - - USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) - ; - static const size_t _max_tx_bytes_per_packet = - USRP2_UDP_BYTES - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used - ; - + //io impl methods and members std::vector _data_transports; - uhd::otw_type_t _rx_otw_type, _tx_otw_type; + const usrp2_io_helper _io_helper; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); }; -- cgit v1.2.3 From deaade7bd0ae4dd9cab7f304fb69eea153ce592a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 17:44:47 -0700 Subject: uhd: renamed the vrt header to vrt_if_packet header --- host/include/uhd/transport/CMakeLists.txt | 2 +- host/include/uhd/transport/vrt.hpp | 99 ------------ host/include/uhd/transport/vrt_if_packet.hpp | 99 ++++++++++++ host/lib/transport/CMakeLists.txt | 4 +- host/lib/transport/gen_vrt.py | 233 --------------------------- host/lib/transport/gen_vrt_if_packet.py | 233 +++++++++++++++++++++++++++ host/lib/transport/vrt_packet_handler.hpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- host/test/vrt_test.cpp | 2 +- 9 files changed, 338 insertions(+), 338 deletions(-) delete mode 100644 host/include/uhd/transport/vrt.hpp create mode 100644 host/include/uhd/transport/vrt_if_packet.hpp delete mode 100755 host/lib/transport/gen_vrt.py create mode 100755 host/lib/transport/gen_vrt_if_packet.py (limited to 'host/lib') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 23a4aae94..4e1f7aca5 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -23,7 +23,7 @@ INSTALL(FILES if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp - vrt.hpp + vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp deleted file mode 100644 index 17da2d540..000000000 --- a/host/include/uhd/transport/vrt.hpp +++ /dev/null @@ -1,99 +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_TRANSPORT_VRT_HPP -#define INCLUDED_UHD_TRANSPORT_VRT_HPP - -#include -#include -#include //size_t - -namespace uhd{ namespace transport{ - -namespace vrt{ - - //! The maximum number of 32-bit words in a vrt if packet header - static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf - - /*! - * Definition for fields that can be packed into a vrt if header. - * The size fields are used for input and output depending upon - * the operation used (ie the pack or unpack function call). - */ - struct UHD_API if_packet_info_t{ - //size fields - size_t num_payload_words32; //required in pack, derived in unpack - size_t num_header_words32; //derived in pack, derived in unpack - size_t num_packet_words32; //derived in pack, required in unpack - - //header fields - size_t packet_count; - bool sob, eob; - - //optional fields - bool has_sid; boost::uint32_t sid; - bool has_cid; boost::uint64_t cid; - bool has_tsi; boost::uint32_t tsi; - bool has_tsf; boost::uint64_t tsf; - bool has_tlr; boost::uint32_t tlr; - }; - - /*! - * Pack a vrt header from metadata (big endian format). - * \param packet_buff memory to write the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_pack_be( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Unpack a vrt header to metadata (big endian format). - * \param packet_buff memory to read the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_unpack_be( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Pack a vrt header from metadata (little endian format). - * \param packet_buff memory to write the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_pack_le( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Unpack a vrt header to metadata (little endian format). - * \param packet_buff memory to read the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_unpack_le( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - -} //namespace vrt - -}} //namespace - -#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */ diff --git a/host/include/uhd/transport/vrt_if_packet.hpp b/host/include/uhd/transport/vrt_if_packet.hpp new file mode 100644 index 000000000..ccefe14ea --- /dev/null +++ b/host/include/uhd/transport/vrt_if_packet.hpp @@ -0,0 +1,99 @@ +// +// 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_TRANSPORT_VRT_IF_PACKET_HPP +#define INCLUDED_UHD_TRANSPORT_VRT_IF_PACKET_HPP + +#include +#include +#include //size_t + +namespace uhd{ namespace transport{ + +namespace vrt{ + + //! The maximum number of 32-bit words in a vrt if packet header + static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf + + /*! + * Definition for fields that can be packed into a vrt if header. + * The size fields are used for input and output depending upon + * the operation used (ie the pack or unpack function call). + */ + struct UHD_API if_packet_info_t{ + //size fields + size_t num_payload_words32; //required in pack, derived in unpack + size_t num_header_words32; //derived in pack, derived in unpack + size_t num_packet_words32; //derived in pack, required in unpack + + //header fields + size_t packet_count; + bool sob, eob; + + //optional fields + bool has_sid; boost::uint32_t sid; + bool has_cid; boost::uint64_t cid; + bool has_tsi; boost::uint32_t tsi; + bool has_tsf; boost::uint64_t tsf; + bool has_tlr; boost::uint32_t tlr; + }; + + /*! + * Pack a vrt header from metadata (big endian format). + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_be( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a vrt header to metadata (big endian format). + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_be( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Pack a vrt header from metadata (little endian format). + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_le( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a vrt header to metadata (little endian format). + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_le( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + +} //namespace vrt + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_VRT_IF_PACKET_HPP */ diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 70cf6312d..bde2b72b9 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -50,8 +50,8 @@ ENDIF(HAVE_IFADDRS_H) # Append to the list of sources for lib uhd ######################################################################## LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_SOURCE_DIR}/lib/transport/gen_vrt.py - ${CMAKE_BINARY_DIR}/lib/transport/vrt.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/gen_vrt_if_packet.py + ${CMAKE_BINARY_DIR}/lib/transport/vrt_if_packet.cpp ) LIBUHD_PYTHON_GEN_SOURCE( diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py deleted file mode 100755 index 06182bd39..000000000 --- a/host/lib/transport/gen_vrt.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env python -# -# 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 . -# - -""" -The vrt packer/unpacker code generator: - -This script will generate the pack and unpack routines that convert -metatdata into vrt headers and vrt headers into metadata. - -The generated code infers jump tables to speed-up the parsing time. -""" - -TMPL_TEXT = """ -#import time -/*********************************************************************** - * This file was generated by $file on $time.strftime("%c") - **********************************************************************/ - -\#include -\#include -\#include -\#include - -//define the endian macros to convert integers -\#ifdef BOOST_BIG_ENDIAN - \#define BE_MACRO(x) (x) - \#define LE_MACRO(x) uhd::byteswap(x) -\#else - \#define BE_MACRO(x) uhd::byteswap(x) - \#define LE_MACRO(x) (x) -\#endif - -using namespace uhd; -using namespace uhd::transport; - -######################################################################## -#def gen_code($XE_MACRO, $suffix) -######################################################################## - -######################################################################## -## setup predicates -######################################################################## -#set $sid_p = 0b00001 -#set $cid_p = 0b00010 -#set $tsi_p = 0b00100 -#set $tsf_p = 0b01000 -#set $tlr_p = 0b10000 - -static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ - *(reinterpret_cast(mem)) = $(XE_MACRO)(num); -} - -void vrt::if_hdr_pack_$(suffix)( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info -){ - boost::uint32_t vrt_hdr_flags = 0; - - boost::uint8_t pred = 0; - if (if_packet_info.has_sid) pred |= $hex($sid_p); - if (if_packet_info.has_cid) pred |= $hex($cid_p); - if (if_packet_info.has_tsi) pred |= $hex($tsi_p); - if (if_packet_info.has_tsf) pred |= $hex($tsf_p); - if (if_packet_info.has_tlr) pred |= $hex($tlr_p); - - switch(pred){ - #for $pred in range(2**5) - case $pred: - #set $num_header_words = 1 - #set $flags = 0 - ########## Stream ID ########## - #if $pred & $sid_p - packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); - #set $num_header_words += 1 - #set $flags |= (0x1 << 28); - #end if - ########## Class ID ########## - #if $pred & $cid_p - pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); - #set $num_header_words += 2 - #set $flags |= (0x1 << 27); - #end if - ########## Integer Time ########## - #if $pred & $tsi_p - packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); - #set $num_header_words += 1 - #set $flags |= (0x3 << 22); - #end if - ########## Fractional Time ########## - #if $pred & $tsf_p - pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 - #set $flags |= (0x1 << 20); - #end if - ########## Trailer ########## - #if $pred & $tlr_p - //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); - #set $flags |= (0x1 << 26); - #set $num_trailer_words = 1; - #else - //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; - #set $num_trailer_words = 0; - #end if - ########## Variables ########## - if_packet_info.num_header_words32 = $num_header_words; - if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; - vrt_hdr_flags = $hex($flags); - break; - #end for - } - - //set the burst flags - if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); - if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); - - //fill in complete header word - packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 - | vrt_hdr_flags - | ((if_packet_info.packet_count & 0xf) << 16) - | (if_packet_info.num_packet_words32 & 0xffff) - )); -} - -static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ - num = $(XE_MACRO)(*reinterpret_cast(mem)); -} - -void vrt::if_hdr_unpack_$(suffix)( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info -){ - //extract vrt header - boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); - size_t packet_words32 = vrt_hdr_word & 0xffff; - if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; - - //failure cases - if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) - throw std::runtime_error("bad vrt header or packet fragment"); - if (vrt_hdr_word & (0x7 << 29)) - throw std::runtime_error("unsupported vrt packet type"); - - boost::uint8_t pred = 0; - if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); - if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); - if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); - if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); - if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); - - switch(pred){ - #for $pred in range(2**5) - case $pred: - #set $has_time_spec = False - #set $num_header_words = 1 - ########## Stream ID ########## - #if $pred & $sid_p - if_packet_info.has_sid = true; - if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); - #set $num_header_words += 1 - #else - if_packet_info.has_sid = false; - #end if - ########## Class ID ########## - #if $pred & $cid_p - if_packet_info.has_cid = true; - unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); - #set $num_header_words += 2 - #else - if_packet_info.has_cid = false; - #end if - ########## Integer Time ########## - #if $pred & $tsi_p - if_packet_info.has_tsi = true; - if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); - #set $num_header_words += 1 - #else - if_packet_info.has_tsi = false; - #end if - ########## Fractional Time ########## - #if $pred & $tsf_p - if_packet_info.has_tsf = true; - unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 - #else - if_packet_info.has_tsf = false; - #end if - ########## Trailer ########## - #if $pred & $tlr_p - if_packet_info.has_tlr = true; - if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); - #set $num_trailer_words = 1; - #else - if_packet_info.has_tlr = false; - #set $num_trailer_words = 0; - #end if - ########## Variables ########## - if_packet_info.num_header_words32 = $num_header_words; - if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); - break; - #end for - } -} - -######################################################################## -#end def -######################################################################## - -$gen_code("BE_MACRO", "be") -$gen_code("LE_MACRO", "le") -""" - -def parse_tmpl(_tmpl_text, **kwargs): - from Cheetah.Template import Template - return str(Template(_tmpl_text, kwargs)) - -if __name__ == '__main__': - import sys - open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__)) diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py new file mode 100755 index 000000000..536409b2e --- /dev/null +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python +# +# 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 . +# + +""" +The vrt packer/unpacker code generator: + +This script will generate the pack and unpack routines that convert +metatdata into vrt headers and vrt headers into metadata. + +The generated code infers jump tables to speed-up the parsing time. +""" + +TMPL_TEXT = """ +#import time +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#include +\#include +\#include +\#include + +//define the endian macros to convert integers +\#ifdef BOOST_BIG_ENDIAN + \#define BE_MACRO(x) (x) + \#define LE_MACRO(x) uhd::byteswap(x) +\#else + \#define BE_MACRO(x) uhd::byteswap(x) + \#define LE_MACRO(x) (x) +\#endif + +using namespace uhd; +using namespace uhd::transport; + +######################################################################## +#def gen_code($XE_MACRO, $suffix) +######################################################################## + +######################################################################## +## setup predicates +######################################################################## +#set $sid_p = 0b00001 +#set $cid_p = 0b00010 +#set $tsi_p = 0b00100 +#set $tsf_p = 0b01000 +#set $tlr_p = 0b10000 + +static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ + *(reinterpret_cast(mem)) = $(XE_MACRO)(num); +} + +void vrt::if_hdr_pack_$(suffix)( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ + boost::uint32_t vrt_hdr_flags = 0; + + boost::uint8_t pred = 0; + if (if_packet_info.has_sid) pred |= $hex($sid_p); + if (if_packet_info.has_cid) pred |= $hex($cid_p); + if (if_packet_info.has_tsi) pred |= $hex($tsi_p); + if (if_packet_info.has_tsf) pred |= $hex($tsf_p); + if (if_packet_info.has_tlr) pred |= $hex($tlr_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $num_header_words = 1 + #set $flags = 0 + ########## Stream ID ########## + #if $pred & $sid_p + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); + #set $num_header_words += 1 + #set $flags |= (0x1 << 28); + #end if + ########## Class ID ########## + #if $pred & $cid_p + pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #set $flags |= (0x1 << 27); + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); + #set $num_header_words += 1 + #set $flags |= (0x3 << 22); + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #set $flags |= (0x1 << 20); + #end if + ########## Trailer ########## + #if $pred & $tlr_p + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); + #set $flags |= (0x1 << 26); + #set $num_trailer_words = 1; + #else + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; + vrt_hdr_flags = $hex($flags); + break; + #end for + } + + //set the burst flags + if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); + if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); + + //fill in complete header word + packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 + | vrt_hdr_flags + | ((if_packet_info.packet_count & 0xf) << 16) + | (if_packet_info.num_packet_words32 & 0xffff) + )); +} + +static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ + num = $(XE_MACRO)(*reinterpret_cast(mem)); +} + +void vrt::if_hdr_unpack_$(suffix)( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ + //extract vrt header + boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); + size_t packet_words32 = vrt_hdr_word & 0xffff; + if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; + + //failure cases + if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); + if (vrt_hdr_word & (0x7 << 29)) + throw std::runtime_error("unsupported vrt packet type"); + + boost::uint8_t pred = 0; + if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); + if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); + if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); + if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); + if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $has_time_spec = False + #set $num_header_words = 1 + ########## Stream ID ########## + #if $pred & $sid_p + if_packet_info.has_sid = true; + if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); + #set $num_header_words += 1 + #else + if_packet_info.has_sid = false; + #end if + ########## Class ID ########## + #if $pred & $cid_p + if_packet_info.has_cid = true; + unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_cid = false; + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + if_packet_info.has_tsi = true; + if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); + #set $num_header_words += 1 + #else + if_packet_info.has_tsi = false; + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + if_packet_info.has_tsf = true; + unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_tsf = false; + #end if + ########## Trailer ########## + #if $pred & $tlr_p + if_packet_info.has_tlr = true; + if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); + #set $num_trailer_words = 1; + #else + if_packet_info.has_tlr = false; + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); + break; + #end for + } +} + +######################################################################## +#end def +######################################################################## + +$gen_code("BE_MACRO", "be") +$gen_code("LE_MACRO", "le") +""" + +def parse_tmpl(_tmpl_text, **kwargs): + from Cheetah.Template import Template + return str(Template(_tmpl_text, kwargs)) + +if __name__ == '__main__': + import sys + open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__)) diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 8cbc71008..31b7e6614 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 719cf3f16..df1dba663 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 3f74a836e..b90b2fc15 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -16,7 +16,7 @@ // #include -#include +#include #include using namespace uhd::transport; -- cgit v1.2.3 From 82790f3da8afe646f255da428c5936045f0e2434 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 15:38:06 -0700 Subject: usrp2: some cleanup and tweaks in io impl --- host/lib/usrp/usrp2/io_impl.cpp | 117 ++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 41 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 0c92c33b2..c96528694 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -34,60 +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 alignment_buffer_type; - io_impl(std::vector &zc_ifs); - ~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(); + } - bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs); + 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, size_t index); + //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_running; + bool recv_pirate_crew_raiding; alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(std::vector &zc_ifs): - packet_handler_recv_state(zc_ifs.size()) -{ - //create a large enough booty - size_t num_frames = zc_ifs.at(0)->get_num_recv_frames(); - std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = alignment_buffer_type::make(num_frames, zc_ifs.size()); - - //create a new pirate thread for each zc if (yarr!!) - for (size_t i = 0; i < zc_ifs.size(); i++){ - recv_pirate_crew.create_thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_ifs.at(i), i) - ); - } -} - -usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_crew_running = false; - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); -} - -bool usrp2_impl::io_impl::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)); -} - -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index){ +/*********************************************************************** + * 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_crew_running = true; - while(recv_pirate_crew_running){ + recv_pirate_crew_raiding = true; + while(recv_pirate_crew_raiding){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - //TODO unpack vrt, get time spec, round to nearest packet bound, use below: - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff, time_spec_t(/*todoseq*/), index); + 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(), 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; + } } } @@ -103,11 +124,25 @@ void usrp2_impl::io_init(void){ send_buff->commit(sizeof(data)); } - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; + //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(); //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transports)); + _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 + )); + } + + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; + std::cout << "Recv pirate num frames: " << num_frames << std::endl; } /*********************************************************************** -- cgit v1.2.3 From 3b1473d5a3fbfb89e9ddc5575e855644707718d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 16:08:33 -0700 Subject: usrp2: removed usrp2.hpp header, its not needed, just use the discovery/factory system uhd: added usrp_mimo skeleton code/header --- host/include/uhd/usrp/CMakeLists.txt | 6 ++-- host/include/uhd/usrp/mimo_usrp.hpp | 69 ++++++++++++++++++++++++++++++++++++ host/include/uhd/usrp/usrp2.hpp | 62 -------------------------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 22 ++++++------ host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- host/utils/usrp2_addr_burner.cpp | 5 +-- 6 files changed, 87 insertions(+), 79 deletions(-) create mode 100644 host/include/uhd/usrp/mimo_usrp.hpp delete mode 100644 host/include/uhd/usrp/usrp2.hpp (limited to 'host/lib') diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index bbd124ed8..6f8c1a2d8 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -31,12 +31,12 @@ INSTALL(FILES dboard_iface.hpp dboard_manager.hpp - ### usrp headers ### - usrp2.hpp - ### utilities ### tune_helper.hpp + + ### interfaces ### simple_usrp.hpp + mimo_usrp.hpp DESTINATION ${INCLUDE_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp new file mode 100644 index 000000000..2262b324e --- /dev/null +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -0,0 +1,69 @@ +// +// 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_USRP_MIMO_USRP_HPP +#define INCLUDED_UHD_USRP_MIMO_USRP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uhd{ namespace usrp{ + +/*! + * The MIMO USRP device class: + * A mimo usrp facilitates ease-of-use for multi-usrp scenarios. + * The wrapper provides convenience functions to control the group + * of underlying devices as if they consisted of a single device. + */ +class UHD_API mimo_usrp : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new mimo usrp from the device address. + * \param dev_addr the device address + * \return a new mimo usrp object + */ + static sptr make(const device_addr_t &dev_addr); + + /*! + * Get the underlying device object. + * This is needed to get access to the streaming API and properties. + * \return the device object within this simple usrp + */ + virtual device::sptr get_device(void) = 0; + + /*! + * Get a printable name for this mimo usrp. + * \return a printable string + */ + virtual std::string get_name(void) = 0; + + //TODO + +}; + +}} + +#endif /* INCLUDED_UHD_USRP_MIMO_USRP_HPP */ diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp deleted file mode 100644 index 7387e5dd4..000000000 --- a/host/include/uhd/usrp/usrp2.hpp +++ /dev/null @@ -1,62 +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_USRP_USRP2_HPP -#define INCLUDED_UHD_USRP_USRP2_HPP - -#include -#include - -namespace uhd{ namespace usrp{ - -/*! - * The usrp2 device class. - */ -class UHD_API usrp2 : public device{ -public: - /*! - * Find usrp2 devices over the ethernet. - * - * Recommended key/value pairs for the device hint address: - * hint["addr"] = address, where address is a resolvable address - * or ip address, which may or may not be a broadcast address. - * - * Other optional device address keys: - * recv_buff_size: resizes the recv buffer on the data socket - * send_buff_size: resizes the send buffer on the data socket - * - * \param hint a device addr with the usrp2 address filled in - * \return a vector of device addresses for all usrp2s found - */ - static device_addrs_t find(const device_addr_t &hint); - - /*! - * Make a usrp2 from a device address. - * - * Required key/value pairs for the device address: - * hint["addr"] = address, where address is a resolvable address - * or ip address, which must be the specific address of a usrp2. - * - * \param addr the device address - * \return a device sptr to a new usrp2 - */ - static device::sptr make(const device_addr_t &addr); -}; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_USRP2_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 436146a48..cdba19f50 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -35,10 +35,6 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -UHD_STATIC_BLOCK(register_usrp2_device){ - device::register_device(&usrp2::find, &usrp2::make); -} - /*********************************************************************** * Helper Functions **********************************************************************/ @@ -48,10 +44,14 @@ std::vector split_addrs(const std::string &addrs_str){ return addrs; } +template std::string num2str(T num){ + return boost::lexical_cast(num); +} + /*********************************************************************** * Discovery over the udp transport **********************************************************************/ -uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ +static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){ device_addrs_t usrp2_addrs; //return an empty list of addresses when type is set to non-usrp2 @@ -68,7 +68,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ new_hint["addr"] = if_addrs.bcast; //call discover with the new hint and append results - device_addrs_t new_usrp2_addrs = usrp2::find(new_hint); + device_addrs_t new_usrp2_addrs = usrp2_find(new_hint); usrp2_addrs.insert(usrp2_addrs.begin(), new_usrp2_addrs.begin(), new_usrp2_addrs.end() ); @@ -127,11 +127,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -template std::string num2str(T num){ - return boost::lexical_cast(num); -} - -device::sptr usrp2::make(const device_addr_t &device_addr){ +static device::sptr usrp2_make(const device_addr_t &device_addr){ //extract the receive and send buffer sizes size_t recv_buff_size = 0, send_buff_size= 0 ; if (device_addr.has_key("recv_buff_size")){ @@ -161,6 +157,10 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ ); } +UHD_STATIC_BLOCK(register_usrp2_device){ + device::register_device(&usrp2_find, &usrp2_make); +} + /*********************************************************************** * Structors **********************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index df1dba663..07e29eadd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,7 @@ #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include "serdes_ctrl.hpp" -#include +#include #include #include #include diff --git a/host/utils/usrp2_addr_burner.cpp b/host/utils/usrp2_addr_burner.cpp index 08fc1e218..f0e3434b7 100644 --- a/host/utils/usrp2_addr_burner.cpp +++ b/host/utils/usrp2_addr_burner.cpp @@ -16,7 +16,7 @@ // #include -#include +#include #include #include #include @@ -45,6 +45,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //load the options into the address uhd::device_addr_t device_addr; + device_addr["type"] = "usrp2"; if (vm.count("addr")){ device_addr["addr"] = vm["addr"].as(); } @@ -54,7 +55,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } //create a usrp2 device - uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr); + uhd::device::sptr u2_dev = uhd::device::make(device_addr); //FIXME usees the default mboard for now (until the mimo link is supported) wax::obj u2_mb = (*u2_dev)[uhd::usrp::DEVICE_PROP_MBOARD]; std::cout << std::endl; -- cgit v1.2.3 From 6469d2419f8564c37f8fd6870aedbc990f06e108 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 18:32:37 -0700 Subject: uhd: filling in mimo usrp implementation, renamed get_name to get_pp_string for simple and mimo usrp --- host/examples/benchmark_rx_rate.cpp | 2 +- host/examples/rx_timed_samples.cpp | 2 +- host/examples/tx_timed_samples.cpp | 2 +- host/include/uhd/usrp/mimo_usrp.hpp | 41 +++++++++- host/include/uhd/usrp/simple_usrp.hpp | 16 ++-- host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/mimo_usrp.cpp | 149 ++++++++++++++++++++++++++++++++++ host/lib/usrp/simple_usrp.cpp | 12 +-- host/lib/usrp/usrp2/usrp2_impl.cpp | 3 +- 9 files changed, 208 insertions(+), 20 deletions(-) create mode 100644 host/lib/usrp/mimo_usrp.cpp (limited to 'host/lib') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 53f4a3c68..e7e358e4c 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -124,7 +124,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); - std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; sdev->set_rx_rate(500e3); //initial rate while(true){ diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 8db312690..3c3c3fdc6 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -59,7 +59,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); - std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; //set properties on the device std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl; diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 333f03fbe..846d9b6f4 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -61,7 +61,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); - std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; //set properties on the device std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 2262b324e..8820c91c1 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -58,9 +58,46 @@ public: * Get a printable name for this mimo usrp. * \return a printable string */ - virtual std::string get_name(void) = 0; + virtual std::string get_pp_string(void) = 0; - //TODO + /*! + * Get the number of channels in this mimo configuration. + * The number of rx channels == the number of tx channels. + * \return the number of channels + */ + virtual size_t get_num_channels(void) = 0; + + /******************************************************************* + * Misc + ******************************************************************/ + /*! + * Set the time registers on the usrp at the next pps tick. + * The values will not be latched in until the pulse occurs. + * It is recommended that the user sleep(1) after calling to ensure + * that the time registers will be in a known state prior to use. + * + * Note: Because this call sets the time on the "next" pps, + * the seconds in the time spec should be current seconds + 1. + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /*! + * Issue a stream command to the usrp device. + * This tells the usrp to send samples into the host. + * See the documentation for stream_cmd_t for more info. + * \param stream_cmd the stream command to issue + */ + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + + /******************************************************************* + * TX methods + ******************************************************************/ }; diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 6ba1b90dd..1d817e030 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -58,7 +58,7 @@ public: * Get a printable name for this simple usrp. * \return a printable string */ - virtual std::string get_name(void) = 0; + virtual std::string get_pp_string(void) = 0; /******************************************************************* * Misc @@ -98,13 +98,6 @@ public: */ virtual void set_clock_config(const clock_config_t &clock_config) = 0; - /*! - * Read the RSSI value from a usrp device. - * Or throw if the dboard does not support an RSSI readback. - * \return the rssi in dB - */ - virtual float read_rssi(void) = 0; - /******************************************************************* * RX methods ******************************************************************/ @@ -125,6 +118,13 @@ public: virtual bool get_rx_lo_locked(void) = 0; + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \return the rssi in dB + */ + virtual float read_rssi(void) = 0; + /******************************************************************* * TX methods ******************************************************************/ diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 3e12c087e..814affdd0 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -23,6 +23,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp ) diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp new file mode 100644 index 000000000..54c921ac7 --- /dev/null +++ b/host/lib/usrp/mimo_usrp.cpp @@ -0,0 +1,149 @@ +// +// 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * MIMO USRP Implementation + **********************************************************************/ +class mimo_usrp_impl : public mimo_usrp{ +public: + mimo_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + + //extract each mboard and its sub-devices + BOOST_FOREACH(const std::string &name, (*_dev)[DEVICE_PROP_MBOARD_NAMES].as()){ + _mboards.push_back((*_dev)[named_prop_t(DEVICE_PROP_MBOARD, name)]); + _rx_dsps.push_back(_mboards.back()[MBOARD_PROP_RX_DSP]); + _tx_dsps.push_back(_mboards.back()[MBOARD_PROP_TX_DSP]); + + //extract rx subdevice + _rx_dboards.push_back(_mboards.back()[MBOARD_PROP_RX_DBOARD]); + std::string rx_subdev_in_use = _rx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as().at(0); + _rx_subdevs.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]); + + //extract tx subdevice + _tx_dboards.push_back(_mboards.back()[MBOARD_PROP_TX_DBOARD]); + std::string tx_subdev_in_use = _tx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as().at(0); + _tx_subdevs.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]); + } + + //set the clock config across all mboards (TODO set through api) + clock_config_t clock_config; + clock_config.ref_source = clock_config_t::REF_SMA; + clock_config.pps_source = clock_config_t::PPS_SMA; + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + } + + } + + ~mimo_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "MIMO USRP:\n" + " Device: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as() + ); + for (size_t i = 0; i < get_num_channels(); i++){ + buff += str(boost::format( + " Channel: %u\n" + " Mboard: %s\n" + " RX DSP: %s\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + " TX DSP: %s\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % i + % _mboards.at(i)[MBOARD_PROP_NAME].as() + % _rx_dsps.at(i)[DSP_PROP_NAME].as() + % _rx_dboards.at(i)[DBOARD_PROP_NAME].as() + % _rx_subdevs.at(i)[SUBDEV_PROP_NAME].as() + % _tx_dsps.at(i)[DSP_PROP_NAME].as() + % _tx_dboards.at(i)[DBOARD_PROP_NAME].as() + % _tx_subdevs.at(i)[SUBDEV_PROP_NAME].as() + ); + } + return buff; + } + + size_t get_num_channels(void){ + return _mboards.size(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + void set_time_next_pps(const time_spec_t &time_spec){ + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + } + + /******************************************************************* + * RX methods + ******************************************************************/ + + /******************************************************************* + * TX methods + ******************************************************************/ + +private: + device::sptr _dev; + std::vector _mboards; + std::vector _rx_dsps; + std::vector _tx_dsps; + std::vector _rx_dboards; + std::vector _tx_dboards; + std::vector _rx_subdevs; + std::vector _tx_subdevs; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ + return sptr(new mimo_usrp_impl(dev_addr)); +} diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index f4aa82669..4a5171cf7 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -31,7 +31,7 @@ using namespace uhd; using namespace uhd::usrp; /*********************************************************************** - * Simple Device Implementation + * Simple USRP Implementation **********************************************************************/ class simple_usrp_impl : public simple_usrp{ public: @@ -60,7 +60,7 @@ public: return _dev; } - std::string get_name(void){ + std::string get_pp_string(void){ return str(boost::format( "Simple USRP:\n" " Device: %s\n" @@ -102,10 +102,6 @@ public: _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } - float read_rssi(void){ - return _rx_subdev[SUBDEV_PROP_RSSI].as(); - } - /******************************************************************* * RX methods ******************************************************************/ @@ -157,6 +153,10 @@ public: return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as(); } + float read_rssi(void){ + return _rx_subdev[SUBDEV_PROP_RSSI].as(); + } + /******************************************************************* * TX methods ******************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index cdba19f50..3402c26b1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -199,7 +199,8 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ case DEVICE_PROP_NAME: - val = std::string("usrp2 device"); + if (_mboards.size() > 1) val = std::string("usrp2 mimo device"); + else val = std::string("usrp2 device"); return; case DEVICE_PROP_MBOARD: -- cgit v1.2.3 From 09ad8e1337c76ae9ca8bbf18791519fa786a286a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 2 Jul 2010 10:48:43 -0700 Subject: uhd: filled in mimo usrp rx and tx methods --- host/include/uhd/usrp/mimo_usrp.hpp | 40 ++++++++++++ host/include/uhd/utils/algorithm.hpp | 29 +++++++++ host/lib/usrp/mimo_usrp.cpp | 118 +++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 8820c91c1..483feca29 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -94,10 +94,50 @@ public: /******************************************************************* * RX methods ******************************************************************/ + virtual void set_rx_rate_all(double rate) = 0; + virtual double get_rx_rate_all(void) = 0; + + virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0; + virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0; + virtual freq_range_t get_rx_freq_range(size_t chan) = 0; + + virtual void set_rx_gain(size_t chan, float gain) = 0; + virtual float get_rx_gain(size_t chan) = 0; + virtual gain_range_t get_rx_gain_range(size_t chan) = 0; + + virtual void set_rx_antenna(size_t chan, const std::string &ant) = 0; + virtual std::string get_rx_antenna(size_t chan) = 0; + virtual std::vector get_rx_antennas(size_t chan) = 0; + + virtual bool get_rx_lo_locked(size_t chan) = 0; + + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \param chan which mimo channel 0 to N-1 + * \return the rssi in dB + */ + virtual float read_rssi(size_t chan) = 0; /******************************************************************* * TX methods ******************************************************************/ + virtual void set_tx_rate_all(double rate) = 0; + virtual double get_tx_rate_all(void) = 0; + + virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0; + virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0; + virtual freq_range_t get_tx_freq_range(size_t chan) = 0; + + virtual void set_tx_gain(size_t chan, float gain) = 0; + virtual float get_tx_gain(size_t chan) = 0; + virtual gain_range_t get_tx_gain_range(size_t chan) = 0; + + virtual void set_tx_antenna(size_t chan, const std::string &ant) = 0; + virtual std::string get_tx_antenna(size_t chan) = 0; + virtual std::vector get_tx_antennas(size_t chan) = 0; + + virtual bool get_tx_lo_locked(size_t chan) = 0; }; diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index 08977a69f..b52edc6b5 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -82,6 +82,35 @@ namespace std{ return boost::end(range) != std::find(boost::begin(range), boost::end(range), value); } + /*! + * Count the number of appearances of a value in a range. + * + * Uses std::count to count the appearances in the range. + * + * \param range the elements to iterate through + * \param value the value to count in the range + * \return the number of appearances of the value + */ + template inline + size_t count(const Range &range, const T &value){ + return std::count(boost::begin(range), boost::end(range), value); + } + + /*! + * Are the ranges equal (are their elements equivalent)? + * + * Uses std::equal to search the iterable for an element. + * + * \param range1 the first range of elements + * \param range2 the second range of elements + * \return true when the elements are equivalent + */ + template inline + bool equal(const Range &range1, const Range &range2){ + return (boost::size(range1) == boost::size(range2)) and + std::equal(boost::begin(range1), boost::end(range1), boost::begin(range2)); + } + /*! * A templated signum implementation. * \param n the comparable to process diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 54c921ac7..3c9788388 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -125,10 +126,124 @@ public: /******************************************************************* * RX methods ******************************************************************/ + void set_rx_rate_all(double rate){ + std::vector _actual_rates; + BOOST_FOREACH(wax::obj rx_dsp, _rx_dsps){ + rx_dsp[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(rx_dsp[DSP_PROP_HOST_RATE].as()); + } + _rx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: rx rate inconsistent across mboards" + ); + } + + double get_rx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_rx_freq(size_t chan, double target_freq){ + return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq); + } + + tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ + return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq, lo_off); + } + + freq_range_t get_rx_freq_range(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as(); + } + + void set_rx_gain(size_t chan, float gain){ + _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; + } + + float get_rx_gain(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as(); + } + + void set_rx_antenna(size_t chan, const std::string &ant){ + _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_rx_antennas(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + float read_rssi(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_RSSI].as(); + } /******************************************************************* * TX methods ******************************************************************/ + void set_tx_rate_all(double rate){ + std::vector _actual_rates; + BOOST_FOREACH(wax::obj tx_dsp, _tx_dsps){ + tx_dsp[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(tx_dsp[DSP_PROP_HOST_RATE].as()); + } + _tx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: tx rate inconsistent across mboards" + ); + } + + double get_tx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_tx_freq(size_t chan, double target_freq){ + return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq); + } + + tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ + return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq, lo_off); + } + + freq_range_t get_tx_freq_range(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as(); + } + + void set_tx_gain(size_t chan, float gain){ + _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; + } + + float get_tx_gain(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as(); + } + + void set_tx_antenna(size_t chan, const std::string &ant){ + _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_tx_antennas(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } private: device::sptr _dev; @@ -139,6 +254,9 @@ private: std::vector _tx_dboards; std::vector _rx_subdevs; std::vector _tx_subdevs; + + //shadows + double _rx_rate, _tx_rate; }; /*********************************************************************** -- cgit v1.2.3 From 37bc860d52c937fb35925af3590d9bca1ecad559 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 2 Jul 2010 18:29:19 -0700 Subject: mimo: added call to set time to zero at next pps on init --- host/include/uhd/usrp/mimo_usrp.hpp | 1 + host/lib/usrp/mimo_usrp.cpp | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 483feca29..a3cbde483 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -75,6 +75,7 @@ public: * The values will not be latched in until the pulse occurs. * It is recommended that the user sleep(1) after calling to ensure * that the time registers will be in a known state prior to use. + * This call works across all mboards in the mimo configuration. * * Note: Because this call sets the time on the "next" pps, * the seconds in the time spec should be current seconds + 1. diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 3c9788388..bd7753d09 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -64,6 +64,10 @@ public: mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } + //set the times to zero at the next pps and sleep + this->set_time_next_pps(time_spec_t(0, 0)); + sleep(1); + } ~mimo_usrp_impl(void){ -- cgit v1.2.3 From 11f2aa1ea0fd6c28a20c6d85f94e41a06b3a6770 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 3 Jul 2010 16:50:45 -0700 Subject: uhd: replaced old send and recv with inline wrappers that take a single buffer and look more like the vectored send/recv --- host/examples/benchmark_rx_rate.cpp | 4 +-- host/examples/rx_timed_samples.cpp | 2 +- host/examples/tx_timed_samples.cpp | 4 +-- host/include/uhd/device.hpp | 53 +++++++++++++++++-------------- host/lib/transport/vrt_packet_handler.hpp | 1 - 5 files changed, 34 insertions(+), 30 deletions(-) (limited to 'host/lib') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index e7e358e4c..6984d7eff 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -49,7 +49,7 @@ static inline void test_device( sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); do { size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); @@ -79,7 +79,7 @@ static inline void test_device( //flush the buffers while(dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET )); diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 3c3c3fdc6..9ff8772bc 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -85,7 +85,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::rx_metadata_t md; std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 846d9b6f4..4226aa4c8 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -81,8 +81,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //send the entire buffer, let the driver handle fragmentation size_t num_tx_samps = dev->send( - boost::asio::buffer(buff), - md, uhd::io_type_t::COMPLEX_FLOAT32, + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::SEND_MODE_FULL_BUFF ); std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index f04a5b4fb..e5ef1181f 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include namespace uhd{ @@ -97,20 +96,6 @@ public: RECV_MODE_ONE_PACKET = 1 }; - //! wrapper call for single buffer recv //TODO put somewhere - size_t send( - const boost::asio::const_buffer &buff, - const tx_metadata_t &metadata, - const io_type_t &io_type, - send_mode_t send_mode - ){ - return send( - std::vector(1, boost::asio::buffer_cast(buff)), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, send_mode - ); - } - /*! * Send buffers containing IF data described by the metadata. * @@ -140,17 +125,20 @@ public: send_mode_t send_mode ) = 0; - //! wrapper call for single buffer recv //TODO put somewhere - size_t recv( - const boost::asio::mutable_buffer &buff, - rx_metadata_t &metadata, + /*! + * Convenience wrapper for send that takes a single buffer. + */ + inline size_t send( + const void *buff, + size_t nsamps_per_buff, + const tx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode + send_mode_t send_mode ){ - return recv( - std::vector(1, boost::asio::buffer_cast(buff)), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, recv_mode + return send( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, send_mode ); } @@ -195,6 +183,23 @@ public: recv_mode_t recv_mode ) = 0; + /*! + * Convenience wrapper for recv that takes a single buffer. + */ + inline size_t recv( + void *buff, + size_t nsamps_per_buff, + rx_metadata_t &metadata, + const io_type_t &io_type, + recv_mode_t recv_mode + ){ + return recv( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, recv_mode + ); + } + /*! * Get the maximum number of samples per packet on send. * \return the number of samples diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 31b7e6614..42cbb7e5a 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 5e14653f241070791d46893e68e341357e040add Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 4 Jul 2010 19:13:59 -0700 Subject: usrp2: bug fix for readback registers added readback for time64 fixed bug for fragment flag in vrt packet handler --- host/include/uhd/transport/zero_copy.hpp | 8 ++++---- host/include/uhd/usrp/mboard_props.hpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 18 +++++++++--------- host/lib/usrp/usrp2/fw_common.h | 2 +- host/lib/usrp/usrp2/mboard_impl.cpp | 10 ++++++++++ host/lib/usrp/usrp2/usrp2_regs.hpp | 10 ++++++---- 6 files changed, 31 insertions(+), 19 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 2815e3189..da10bfbe2 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -47,7 +47,7 @@ namespace uhd{ namespace transport{ * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void) const{ + inline size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -55,7 +55,7 @@ namespace uhd{ namespace transport{ * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void) const{ + template inline T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -89,7 +89,7 @@ namespace uhd{ namespace transport{ * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void) const{ + inline size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -97,7 +97,7 @@ namespace uhd{ namespace transport{ * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void) const{ + template inline T cast(void) const{ return boost::asio::buffer_cast(this->get()); } diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp index 7ff454472..a432ce50c 100644 --- a/host/include/uhd/usrp/mboard_props.hpp +++ b/host/include/uhd/usrp/mboard_props.hpp @@ -40,7 +40,7 @@ namespace uhd{ namespace usrp{ MBOARD_PROP_TX_DBOARD = 'v', //ro, wax::obj MBOARD_PROP_TX_DBOARD_NAMES = 'V', //ro, prop_names_t MBOARD_PROP_CLOCK_CONFIG = 'C', //rw, clock_config_t - MBOARD_PROP_TIME_NOW = 't', //wo, time_spec_t + MBOARD_PROP_TIME_NOW = 't', //rw, time_spec_t MBOARD_PROP_TIME_NEXT_PPS = 'T', //wo, time_spec_t MBOARD_PROP_STREAM_CMD = 's' //wo, stream_cmd_t }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 42cbb7e5a..177239509 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -151,20 +151,15 @@ namespace vrt_packet_handler{ //extract the number of samples available to copy size_t bytes_per_item = otw_type.get_sample_size(); size_t bytes_available = state.size_of_copy_buffs; - size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); - size_t bytes_to_copy = num_samps*bytes_per_item; - - //setup the fragment flags and offset - metadata.more_fragments = total_samps < num_samps; - metadata.fragment_offset = state.fragment_offset_in_samps; - state.fragment_offset_in_samps += num_samps; //set for next call + size_t nsamps_to_copy = std::min(total_samps, bytes_available/bytes_per_item); + size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; for (size_t i = 0; i < state.width; i++){ //copy-convert the samples from the recv buffer uhd::transport::convert_otw_type_to_io_type( state.copy_buffs[i], otw_type, reinterpret_cast(buffs[i]) + offset_bytes, - io_type, num_samps + io_type, nsamps_to_copy ); //update the rx copy buffer to reflect the bytes copied @@ -173,7 +168,12 @@ namespace vrt_packet_handler{ //update the copy buffer's availability state.size_of_copy_buffs -= bytes_to_copy; - return num_samps; + //setup the fragment flags and offset + metadata.more_fragments = state.size_of_copy_buffs != 0; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += nsamps_to_copy; //set for next call + + return nsamps_to_copy; } /******************************************************************* diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 242d268ec..12daa6286 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -38,7 +38,7 @@ extern "C" { //defines the protocol version in this shared header //increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 4 +#define USRP2_PROTO_VERSION 5 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 28a346be7..36ac6275f 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -72,6 +73,7 @@ usrp2_mboard_impl::usrp2_mboard_impl( ); _iface->poke32(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); + _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); //init the ddc init_ddc_config(); @@ -254,6 +256,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; + case MBOARD_PROP_TIME_NOW: + val = time_spec_t( + _iface->peek32(U2_REG_TIME64_SECS_RB), + _iface->peek32(U2_REG_TIME64_TICKS_RB), + get_master_clock_freq() + ); + return; + default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 589fa71a3..c859d3603 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -18,8 +18,6 @@ #ifndef INCLUDED_USRP2_REGS_HPP #define INCLUDED_USRP2_REGS_HPP -#include - //////////////////////////////////////////////////// // Settings Bus, Slave #7, Not Byte Addressable! // @@ -46,7 +44,7 @@ #define SR_SIMTIMER 198 #define SR_LAST 255 -#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(boost::uint32_t)) +#define _SR_ADDR(sr) ((MISC_OUTPUT_BASE) + (4*(sr))) ///////////////////////////////////////////////// // SPI Slave Constants @@ -104,7 +102,11 @@ #define U2_REG_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS #define U2_REG_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS #define U2_REG_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above -#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_TPS _SR_ADDR(SR_TIME64 + 4) // the ticks per second rollover count + +#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10) +#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11) //pps flags (see above) #define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -- cgit v1.2.3 From 549a0170a409904f123a4eef975362978ca62bf3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 4 Jul 2010 20:21:09 -0700 Subject: uhd: added get time now call to simple and mimo usrp --- host/include/uhd/usrp/mimo_usrp.hpp | 6 ++++++ host/include/uhd/usrp/simple_usrp.hpp | 6 ++++++ host/lib/usrp/mimo_usrp.cpp | 10 +++++----- host/lib/usrp/simple_usrp.cpp | 4 ++++ 4 files changed, 21 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index a3cbde483..e85c06046 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -70,6 +70,12 @@ public: /******************************************************************* * Misc ******************************************************************/ + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + /*! * Set the time registers on the usrp at the next pps tick. * The values will not be latched in until the pulse occurs. diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 1d817e030..1d9136f08 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -63,6 +63,12 @@ public: /******************************************************************* * Misc ******************************************************************/ + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + /*! * Sets the time registers on the usrp immediately. * \param time_spec the time to latch into the usrp device diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index bd7753d09..440aaf9f6 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -63,11 +63,6 @@ public: BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } - - //set the times to zero at the next pps and sleep - this->set_time_next_pps(time_spec_t(0, 0)); - sleep(1); - } ~mimo_usrp_impl(void){ @@ -115,6 +110,11 @@ public: /******************************************************************* * Misc ******************************************************************/ + time_spec_t get_time_now(void){ + //the time on the first mboard better be the same on all + return _mboards.front()[MBOARD_PROP_TIME_NOW].as(); + } + void set_time_next_pps(const time_spec_t &time_spec){ BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index 4a5171cf7..56e82d7ee 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -86,6 +86,10 @@ public: /******************************************************************* * Misc ******************************************************************/ + time_spec_t get_time_now(void){ + return _mboard[MBOARD_PROP_TIME_NOW].as(); + } + void set_time_now(const time_spec_t &time_spec){ _mboard[MBOARD_PROP_TIME_NOW] = time_spec; } -- cgit v1.2.3 From c2039a8c92561fa5532d87cb9d875a3ad7b875c1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 16:35:44 -0700 Subject: uhd: code tweaks, extra error condition for vrt unpack --- host/lib/transport/gen_vrt_if_packet.py | 7 +++++-- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py index 536409b2e..7910ff60d 100755 --- a/host/lib/transport/gen_vrt_if_packet.py +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -150,10 +150,10 @@ void vrt::if_hdr_unpack_$(suffix)( if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) + if (if_packet_info.num_packet_words32 < packet_words32) throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) - throw std::runtime_error("unsupported vrt packet type"); + throw std::runtime_error("bad vrt header or unsupported packet type"); boost::uint8_t pred = 0; if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); @@ -209,6 +209,9 @@ void vrt::if_hdr_unpack_$(suffix)( #set $num_trailer_words = 0; #end if ########## Variables ########## + //another failure case + if (packet_words32 < $($num_header_words + $num_trailer_words)) + throw std::runtime_error("bad vrt header or invalid packet length"); if_packet_info.num_header_words32 = $num_header_words; if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); break; diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 7f9292d24..a91be25af 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -28,7 +28,7 @@ using namespace uhd::transport; * Constants **********************************************************************/ //enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); +static const size_t MIN_SOCK_BUFF_SIZE(sizeof(boost::uint32_t) * 25e6 * 0.5); static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 177239509..68edeb1e1 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -87,7 +87,7 @@ namespace vrt_packet_handler{ uhd::transport::vrt::if_packet_info_t if_packet_info; for (size_t i = 0; i < state.width; i++){ const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast() + vrt_header_offset_words32; - if_packet_info.num_packet_words32 = num_packet_words32; + if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32; vrt_unpacker(vrt_hdr, if_packet_info); //handle the packet count / sequence number @@ -163,7 +163,7 @@ namespace vrt_packet_handler{ ); //update the rx copy buffer to reflect the bytes copied - state.copy_buffs[i] = reinterpret_cast(state.copy_buffs[i]) + bytes_to_copy; + state.copy_buffs[i] += bytes_to_copy; } //update the copy buffer's availability state.size_of_copy_buffs -= bytes_to_copy; -- cgit v1.2.3 From a95eaac42f6cc85fd2ad3f32dc29eeab38ef5194 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 19:12:01 -0700 Subject: usrp2: Added a peek64 to read pairs of 32 bit numbers such as time64 also added a templated host to/from network conversion in byteswap.hpp (didnt use it though) --- firmware/microblaze/apps/txrx_uhd.c | 8 ++++++++ host/include/uhd/utils/byteswap.hpp | 27 +++++++++++++++++++++++++++ host/lib/usrp/usrp2/fw_common.h | 4 +++- host/lib/usrp/usrp2/mboard_impl.cpp | 14 ++++++++------ host/lib/usrp/usrp2/usrp2_iface.cpp | 24 +++++++++++++++++++----- host/lib/usrp/usrp2/usrp2_iface.hpp | 10 ++++++++++ 6 files changed, 75 insertions(+), 12 deletions(-) (limited to 'host/lib') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 21803b199..99c149d45 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -269,6 +269,10 @@ void handle_udp_ctrl_packet( printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); } else switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint64_t): + *((uint32_t *) ctrl_data_in->data.poke_args.addrhi) = (uint32_t)ctrl_data_in->data.poke_args.datahi; + //continue to uint32_t for low addr: + case sizeof(uint32_t): *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; break; @@ -287,6 +291,10 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint64_t): + ctrl_data_out.data.poke_args.datahi = *((uint32_t *) ctrl_data_in->data.poke_args.addrhi); + //continue to uint32_t for low addr: + case sizeof(uint32_t): ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); break; diff --git a/host/include/uhd/utils/byteswap.hpp b/host/include/uhd/utils/byteswap.hpp index dd5dcbc09..26d60c2ab 100644 --- a/host/include/uhd/utils/byteswap.hpp +++ b/host/include/uhd/utils/byteswap.hpp @@ -37,6 +37,12 @@ namespace uhd{ //! perform a byteswap on a 64 bit integer boost::uint64_t byteswap(boost::uint64_t); + //! network to host: short, long, or long-long + template T ntohx(T); + + //! host to network: short, long, or long-long + template T htonx(T); + } //namespace uhd /*********************************************************************** @@ -117,4 +123,25 @@ namespace uhd{ #endif +/*********************************************************************** + * Define the templated network to/from host conversions + **********************************************************************/ +#include + +template UHD_INLINE T uhd::ntohx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + +template UHD_INLINE T uhd::htonx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + #endif /* INCLUDED_UHD_UTILS_BYTESWAP_HPP */ diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 12daa6286..4c66aa41e 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -111,7 +111,9 @@ typedef struct{ struct { _SINS_ uint32_t addr; _SINS_ uint32_t data; - _SINS_ uint8_t num_bytes; //1, 2, 4 + _SINS_ uint32_t addrhi; + _SINS_ uint32_t datahi; + _SINS_ uint8_t num_bytes; //1, 2, 4, 8 } poke_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 36ac6275f..952954286 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -256,12 +256,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; - case MBOARD_PROP_TIME_NOW: - val = time_spec_t( - _iface->peek32(U2_REG_TIME64_SECS_RB), - _iface->peek32(U2_REG_TIME64_TICKS_RB), - get_master_clock_freq() - ); + case MBOARD_PROP_TIME_NOW:{ + usrp2_iface::pair64 time64( + _iface->peek64(U2_REG_TIME64_SECS_RB, U2_REG_TIME64_TICKS_RB) + ); + val = time_spec_t( + time64.first, time64.second, get_master_clock_freq() + ); + } return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 66a1a57f6..faf4a5c7e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -59,6 +59,20 @@ public: return this->peek(addr); } + pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); + out_data.data.poke_args.addr = htonl(addrlo); + out_data.data.poke_args.addrhi = htonl(addrhi); + out_data.data.poke_args.num_bytes = sizeof(boost::uint64_t); + + //send and recv + usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + return pair64(ntohl(in_data.data.poke_args.data), ntohl(in_data.data.poke_args.datahi)); + } + /*********************************************************************** * SPI **********************************************************************/ @@ -86,7 +100,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); return ntohl(in_data.data.spi_args.data); } @@ -109,7 +123,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); } byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ @@ -124,7 +138,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); //copy out the data @@ -187,7 +201,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); } template T peek(boost::uint32_t addr){ @@ -199,7 +213,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); return T(ntohl(in_data.data.poke_args.data)); } diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 7b2a3a89d..9cc32104e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "fw_common.h" //////////////////////////////////////////////////////////////////////// @@ -49,6 +50,7 @@ class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{ public: typedef boost::shared_ptr sptr; + typedef std::pair pair64; /*! * Make a new usrp2 interface with the control transport. @@ -64,6 +66,14 @@ public: */ virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0; + /*! + * Read a dual register (64 bits) + * \param addrlo the address for the low-32 bits + * \param addrhi the address for the high-32 bits + * \return a pair of 32 bit integers lo, hi + */ + virtual pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi) = 0; + /*! * Write a register (32 bits) * \param addr the address -- cgit v1.2.3 From 189c4c96fc0b40aa98c28f6bd4b95753bdaec970 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 21:51:48 -0700 Subject: uhd: remove windows warnings (minor tweaks) --- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index a91be25af..7f9292d24 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -28,7 +28,7 @@ using namespace uhd::transport; * Constants **********************************************************************/ //enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_SOCK_BUFF_SIZE(sizeof(boost::uint32_t) * 25e6 * 0.5); +static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 07e29eadd..42630a3e4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -114,7 +114,7 @@ private: static const size_t _max_tx_bytes_per_packet = USRP2_UDP_BYTES - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used ; }; -- cgit v1.2.3 From 1ca30a49030da2ef248048e17a46738bb3823c4c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 15:44:15 -0700 Subject: uhd: added set time w/ unknown pps to mimo usrp, get tx rate bug fix --- host/include/uhd/usrp/mimo_usrp.hpp | 18 ++++++++++++++++++ host/lib/usrp/mimo_usrp.cpp | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index e85c06046..68a42cad8 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -90,6 +90,24 @@ public: */ virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + /*! + * Synchronize the times across all motherboards in this configuration. + * Use this method to sync the times when the edge of the PPS is unknown. + * + * Ex: Host machine is not attached to serial port of GPSDO + * and can therefore not query the GPSDO for the PPS edge. + * + * This is a 3-step process, and will take at most 3 seconds to complete. + * Upon completion, the times will be synchronized to the time provided. + * + * - Step1: set the time at the next pps (potential race condition) + * - Step2: wait for the seconds to rollover to catch the pps edge + * - Step3: set the time at the next pps (synchronous for all boards) + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_unknown_pps(const time_spec_t &time_spec) = 0; + /*! * Issue a stream command to the usrp device. * This tells the usrp to send samples into the host. diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 440aaf9f6..f5441e19d 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -121,6 +122,22 @@ public: } } + void set_time_unknown_pps(const time_spec_t &time_spec){ + std::cout << "Set time with unknown pps edge:" << std::endl; + std::cout << " 1) set times next pps (race condition)" << std::endl; + set_time_next_pps(time_spec); sleep(1); + + std::cout << " 2) catch seconds rollover at pps edge" << std::endl; + time_t last_secs = 0, curr_secs = 0; + while(curr_secs == last_secs){ + last_secs = curr_secs; + curr_secs = get_time_now().get_full_secs(); + } + + std::cout << " 3) set times next pps (synchronously)" << std::endl; + set_time_next_pps(time_spec); sleep(1); + } + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; @@ -206,7 +223,7 @@ public: } double get_tx_rate_all(void){ - return _rx_rate; + return _tx_rate; } tune_result_t set_tx_freq(size_t chan, double target_freq){ -- cgit v1.2.3 From 7f3c4791f7d19d02b7d4515c763b9c2044e96170 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 16:55:59 -0700 Subject: uhd: mimo usrp replace sleep with boost thread sleep (windows fix) --- host/lib/usrp/mimo_usrp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index f5441e19d..fd8225074 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -125,7 +126,8 @@ public: void set_time_unknown_pps(const time_spec_t &time_spec){ std::cout << "Set time with unknown pps edge:" << std::endl; std::cout << " 1) set times next pps (race condition)" << std::endl; - set_time_next_pps(time_spec); sleep(1); + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); std::cout << " 2) catch seconds rollover at pps edge" << std::endl; time_t last_secs = 0, curr_secs = 0; @@ -135,7 +137,8 @@ public: } std::cout << " 3) set times next pps (synchronously)" << std::endl; - set_time_next_pps(time_spec); sleep(1); + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); } void issue_stream_cmd(const stream_cmd_t &stream_cmd){ -- cgit v1.2.3