diff options
Diffstat (limited to 'host/lib/transport')
-rw-r--r-- | host/lib/transport/CMakeLists.txt | 5 | ||||
-rw-r--r-- | host/lib/transport/chdr.cpp | 182 | ||||
-rw-r--r-- | host/lib/transport/gen_vrt_if_packet.py | 269 | ||||
-rw-r--r-- | host/lib/transport/libusb1_base.cpp | 48 | ||||
-rw-r--r-- | host/lib/transport/libusb1_base.hpp | 27 | ||||
-rw-r--r-- | host/lib/transport/libusb1_zero_copy.cpp | 73 | ||||
-rwxr-xr-x | host/lib/transport/nirio/lvbitx/process-lvbitx.py | 16 | ||||
-rw-r--r-- | host/lib/transport/nirio/nirio_driver_iface_linux.cpp | 10 | ||||
-rw-r--r-- | host/lib/transport/nirio/niriok_proxy_impl_v1.cpp | 421 | ||||
-rw-r--r-- | host/lib/transport/nirio/niriok_proxy_impl_v2.cpp | 270 | ||||
-rw-r--r-- | host/lib/transport/nirio/rpc/rpc_client.cpp | 2 | ||||
-rw-r--r-- | host/lib/transport/super_recv_packet_handler.hpp | 7 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy.cpp | 9 |
13 files changed, 1088 insertions, 251 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 5920f3d78..6abc399b4 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2013,2015 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 @@ -30,7 +30,7 @@ INCLUDE_SUBDIRECTORY(nirio) MESSAGE(STATUS "") FIND_PACKAGE(USB1) -LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF) +LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF OFF) IF(ENABLE_USB) MESSAGE(STATUS "USB support enabled via libusb.") @@ -129,6 +129,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp ${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp ) # Verbose Debug output for send/recv diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp new file mode 100644 index 000000000..632887e56 --- /dev/null +++ b/host/lib/transport/chdr.cpp @@ -0,0 +1,182 @@ +// +// Copyright 2014 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 <http://www.gnu.org/licenses/>. +// + +#include <uhd/transport/chdr.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/exception.hpp> + +//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::transport::vrt; + +static const boost::uint32_t HDR_FLAG_TSF = (1 << 29); +static const boost::uint32_t HDR_FLAG_EOB = (1 << 28); +static const boost::uint32_t HDR_FLAG_ERROR = (1 << 28); + +/***************************************************************************/ +/* Packing */ +/***************************************************************************/ +/*! Translate the contents of \p if_packet_info into a 32-Bit word and return it. + */ +UHD_INLINE boost::uint32_t _hdr_pack_chdr( + if_packet_info_t &if_packet_info +) { + // Set fields in if_packet_info + if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0); + if_packet_info.num_packet_words32 = + if_packet_info.num_header_words32 + + if_packet_info.num_payload_words32; + + boost::uint16_t pkt_length = + if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32); + boost::uint32_t chdr = 0 + // 2 Bits: Packet type + | (if_packet_info.packet_type << 30) + // 1 Bit: Has time + | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0) + // 1 Bit: EOB or Error + | ((if_packet_info.eob or if_packet_info.error) ? HDR_FLAG_EOB : 0) + // 12 Bits: Sequence number + | ((if_packet_info.packet_count & 0xFFF) << 16) + // 16 Bits: Total packet length + | pkt_length; + return chdr; +} + +void chdr::if_hdr_pack_be( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +) { + // Write header and update if_packet_info + packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info)); + + // Write SID + packet_buff[1] = BE_MACRO(if_packet_info.sid); + + // Write time + if (if_packet_info.has_tsf) { + packet_buff[2] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32)); + packet_buff[3] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0)); + } +} + +void chdr::if_hdr_pack_le( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +) { + // Write header and update if_packet_info + packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info)); + + // Write SID + packet_buff[1] = LE_MACRO(if_packet_info.sid); + + // Write time + if (if_packet_info.has_tsf) { + packet_buff[2] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32)); + packet_buff[3] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0)); + } +} + + +/***************************************************************************/ +/* Unpacking */ +/***************************************************************************/ +UHD_INLINE void _hdr_unpack_chdr( + const boost::uint32_t chdr, + if_packet_info_t &if_packet_info +) { + // Set constant members + if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR; + if_packet_info.has_cid = false; + if_packet_info.has_sid = true; + if_packet_info.has_tsi = false; + if_packet_info.has_tlr = false; + if_packet_info.sob = false; + + // Set configurable members + if_packet_info.has_tsf = (chdr & HDR_FLAG_TSF) > 0; + if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3); + if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA) + && ((chdr & HDR_FLAG_EOB) > 0); + if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP) + && ((chdr & HDR_FLAG_ERROR) > 0); + if_packet_info.packet_count = (chdr >> 16) & 0xFFF; + + // Set packet length variables + if (if_packet_info.has_tsf) { + if_packet_info.num_header_words32 = 4; + } else { + if_packet_info.num_header_words32 = 2; + } + size_t pkt_size_bytes = (chdr & 0xFFFF); + size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0); + // Check lengths match: + if (pkt_size_word32 < if_packet_info.num_header_words32) { + throw uhd::value_error("Bad CHDR or invalid packet length"); + } + if (if_packet_info.num_packet_words32 < pkt_size_word32) { + throw uhd::value_error("Bad CHDR or packet fragment"); + } + if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32); + if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32; +} + +void chdr::if_hdr_unpack_be( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +) { + // Read header and update if_packet_info + boost::uint32_t chdr = BE_MACRO(packet_buff[0]); + _hdr_unpack_chdr(chdr, if_packet_info); + + // Read SID + if_packet_info.sid = BE_MACRO(packet_buff[1]); + + // Read time (has_tsf was updated earlier) + if (if_packet_info.has_tsf) { + if_packet_info.tsf = 0 + | boost::uint64_t(BE_MACRO(packet_buff[2])) << 32 + | BE_MACRO(packet_buff[3]); + } +} + +void chdr::if_hdr_unpack_le( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +) { + // Read header and update if_packet_info + boost::uint32_t chdr = LE_MACRO(packet_buff[0]); + _hdr_unpack_chdr(chdr, if_packet_info); + + // Read SID + if_packet_info.sid = LE_MACRO(packet_buff[1]); + + // Read time (has_tsf was updated earlier) + if (if_packet_info.has_tsf) { + if_packet_info.tsf = 0 + | boost::uint64_t(LE_MACRO(packet_buff[2])) << 32 + | LE_MACRO(packet_buff[3]); + } +} + diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py index 98f6804ae..6723e3a4b 100644 --- a/host/lib/transport/gen_vrt_if_packet.py +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2013,2015 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 @@ -25,26 +25,25 @@ 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 +TMPL_TEXT = """<% import time %> /*********************************************************************** - * This file was generated by $file on $time.strftime("%c") + * This file was generated by ${file} on ${time.strftime("%c")} **********************************************************************/ -\#include <uhd/exception.hpp> -\#include <uhd/transport/vrt_if_packet.hpp> -\#include <uhd/utils/byteswap.hpp> -\#include <boost/detail/endian.hpp> -\#include <vector> +#include <uhd/exception.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/detail/endian.hpp> +#include <vector> //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 +#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; @@ -59,13 +58,13 @@ static pred_table_type get_pred_unpack_table(void) pred_table_type table(1 << 9, 0); //only 9 bits useful here (20-28) for (size_t i = 0; i < table.size(); i++){ boost::uint32_t vrt_hdr_word = i << 20; - if(vrt_hdr_word & $hex(0x1 << 28)) table[i] |= $hex($sid_p); - if(vrt_hdr_word & $hex(0x1 << 27)) table[i] |= $hex($cid_p); - if(vrt_hdr_word & $hex(0x3 << 22)) table[i] |= $hex($tsi_p); - if(vrt_hdr_word & $hex(0x3 << 20)) table[i] |= $hex($tsf_p); - if(vrt_hdr_word & $hex(0x1 << 26)) table[i] |= $hex($tlr_p); - if(vrt_hdr_word & $hex(0x1 << 24)) table[i] |= $hex($eob_p); - if(vrt_hdr_word & $hex(0x1 << 25)) table[i] |= $hex($sob_p); + if(vrt_hdr_word & ${hex(0x1 << 28)}) table[i] |= ${hex(sid_p)}; + if(vrt_hdr_word & ${hex(0x1 << 27)}) table[i] |= ${hex(cid_p)}; + if(vrt_hdr_word & ${hex(0x3 << 22)}) table[i] |= ${hex(tsi_p)}; + if(vrt_hdr_word & ${hex(0x3 << 20)}) table[i] |= ${hex(tsf_p)}; + if(vrt_hdr_word & ${hex(0x1 << 26)}) table[i] |= ${hex(tlr_p)}; + if(vrt_hdr_word & ${hex(0x1 << 24)}) table[i] |= ${hex(eob_p)}; + if(vrt_hdr_word & ${hex(0x1 << 25)}) table[i] |= ${hex(sob_p)}; } return table; } @@ -105,13 +104,12 @@ UHD_INLINE static boost::uint32_t vrt_to_chdr(const boost::uint32_t vrt, const i } ######################################################################## -#def gen_code($XE_MACRO, $suffix) +<%def name="gen_code(XE_MACRO, suffix)"> ######################################################################## - /*********************************************************************** - * interal impl of packing VRT IF header only + * internal impl of packing VRT IF header only **********************************************************************/ -UHD_INLINE void __if_hdr_pack_$(suffix)( +UHD_INLINE void __if_hdr_pack_${suffix}( boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info, boost::uint32_t &vrt_hdr_word32 @@ -119,72 +117,53 @@ UHD_INLINE void __if_hdr_pack_$(suffix)( boost::uint32_t vrt_hdr_flags = 0; pred_type 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); - if (if_packet_info.eob) pred |= $hex($eob_p); - if (if_packet_info.sob) pred |= $hex($sob_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)}; + if (if_packet_info.eob) pred |= ${hex(eob_p)}; + if (if_packet_info.sob) pred |= ${hex(sob_p)}; switch(pred){ - #for $pred in range(2**7) - case $pred: - #set $num_header_words = 1 - #set $flags = 0 + % for pred in range(2**7): + case ${pred}:<% num_header_words = 1 %><% 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 + % if pred & sid_p: + packet_buff[${num_header_words}] = ${XE_MACRO}(if_packet_info.sid);<% num_header_words += 1 %><% flags |= (0x1 << 28) %> + % endif ########## Class ID ########## - #if $pred & $cid_p - packet_buff[$num_header_words] = 0; //not implemented - #set $num_header_words += 1 - packet_buff[$num_header_words] = 0; //not implemented - #set $num_header_words += 1 - #set $flags |= (0x1 << 27); - #end if + % if pred & cid_p: + packet_buff[${num_header_words}] = 0; //not implemented<% num_header_words += 1 %> + packet_buff[${num_header_words}] = 0; //not implemented<% num_header_words += 1 %><% flags |= (0x1 << 27) %> + % endif ########## 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 + % if pred & tsi_p: + packet_buff[${num_header_words}] = ${XE_MACRO}(if_packet_info.tsi);<% num_header_words += 1 %><% flags |= (0x3 << 22) %> + % endif ########## Fractional Time ########## - #if $pred & $tsf_p - packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 32)); - #set $num_header_words += 1 - packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 0)); - #set $num_header_words += 1 - #set $flags |= (0x1 << 20); - #end if + % if pred & tsf_p: + packet_buff[${num_header_words}] = ${XE_MACRO}(boost::uint32_t(if_packet_info.tsf >> 32));<% num_header_words += 1 %> + packet_buff[${num_header_words}] = ${XE_MACRO}(boost::uint32_t(if_packet_info.tsf >> 0));<% num_header_words += 1 %><% flags |= (0x1 << 20) %> + % endif ########## Burst Flags ########## - #if $pred & $eob_p - #set $flags |= (0x1 << 24); - #end if - #if $pred & $sob_p - #set $flags |= (0x1 << 25); - #end if +<% if pred & eob_p: flags |= (0x1 << 24) %><% if pred & sob_p: flags |= (0x1 << 25) %> ########## Trailer ########## - #if $pred & $tlr_p + % if pred & tlr_p: { const size_t empty_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - if_packet_info.num_payload_bytes; if_packet_info.tlr = (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10); } - 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 + packet_buff[${num_header_words}+if_packet_info.num_payload_words32] = ${XE_MACRO}(if_packet_info.tlr);<% flags |= (0x1 << 26) %><% num_trailer_words = 1 %> + % else: +<% num_trailer_words = 0 %> + % endif ########## 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); + 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 + % endfor } //fill in complete header word @@ -197,9 +176,9 @@ UHD_INLINE void __if_hdr_pack_$(suffix)( } /*********************************************************************** - * interal impl of unpacking VRT IF header only + * internal impl of unpacking VRT IF header only **********************************************************************/ -UHD_INLINE void __if_hdr_unpack_$(suffix)( +UHD_INLINE void __if_hdr_unpack_${suffix}( const boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info, const boost::uint32_t vrt_hdr_word32 @@ -219,86 +198,78 @@ UHD_INLINE void __if_hdr_unpack_$(suffix)( size_t empty_bytes = 0; switch(pred){ - #for $pred in range(2**7) - case $pred: - #set $has_time_spec = False - #set $num_header_words = 1 + % for pred in range(2**7): + case ${pred}:<% has_time_spec = False %><% num_header_words = 1 %> ########## Stream ID ########## - #if $pred & $sid_p + % 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.sid = ${XE_MACRO}(packet_buff[${num_header_words}]);<% num_header_words += 1 %> + % else: if_packet_info.has_sid = false; - #end if + % endif ########## Class ID ########## - #if $pred & $cid_p + % if pred & cid_p: if_packet_info.has_cid = true; - if_packet_info.cid = 0; //not implemented - #set $num_header_words += 2 - #else + if_packet_info.cid = 0; //not implemented<% num_header_words += 2 %> + % else: if_packet_info.has_cid = false; - #end if + % endif ########## Integer Time ########## - #if $pred & $tsi_p + % 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.tsi = ${XE_MACRO}(packet_buff[${num_header_words}]); +<% num_header_words += 1 %> + % else: if_packet_info.has_tsi = false; - #end if + % endif ########## Fractional Time ########## - #if $pred & $tsf_p + % if pred & tsf_p: if_packet_info.has_tsf = true; - if_packet_info.tsf = boost::uint64_t($(XE_MACRO)(packet_buff[$num_header_words])) << 32; - #set $num_header_words += 1 - if_packet_info.tsf |= $(XE_MACRO)(packet_buff[$num_header_words]); - #set $num_header_words += 1 - #else + if_packet_info.tsf = boost::uint64_t(${XE_MACRO}(packet_buff[${num_header_words}])) << 32;<% num_header_words += 1 %> + if_packet_info.tsf |= ${XE_MACRO}(packet_buff[${num_header_words}]);<% num_header_words += 1 %> + % else: if_packet_info.has_tsf = false; - #end if + % endif ########## Burst Flags ########## - #if $pred & $eob_p + % if pred & eob_p: if_packet_info.eob = true; - #else + % else: if_packet_info.eob = false; - #end if - #if $pred & $sob_p + % endif + % if pred & sob_p: if_packet_info.sob = true; - #else + % else: if_packet_info.sob = false; - #end if + % endif ########## Trailer ########## - #if $pred & $tlr_p + % if pred & tlr_p: if_packet_info.has_tlr = true; - if_packet_info.tlr = $(XE_MACRO)(packet_buff[packet_words32-1]); - #set $num_trailer_words = 1; + if_packet_info.tlr = ${XE_MACRO}(packet_buff[packet_words32-1]);<% num_trailer_words = 1 %> { const int indicators = (if_packet_info.tlr >> 20) & (if_packet_info.tlr >> 8); if ((indicators & (1 << 0)) != 0) if_packet_info.eob = true; if ((indicators & (1 << 1)) != 0) if_packet_info.sob = true; empty_bytes = occ_table[(indicators >> 2) & 0x3]; } - #else - if_packet_info.has_tlr = false; - #set $num_trailer_words = 0; - #end if + % else: + if_packet_info.has_tlr = false;<% num_trailer_words = 0 %> + % endif ########## Variables ########## //another failure case - if (packet_words32 < $($num_header_words + $num_trailer_words)) + if (packet_words32 < ${num_header_words + num_trailer_words}) throw uhd::value_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); + if_packet_info.num_header_words32 = ${num_header_words}; + if_packet_info.num_payload_words32 = packet_words32 - ${num_header_words + num_trailer_words}; if_packet_info.num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - empty_bytes; break; - #end for + % endfor } } /*********************************************************************** * link layer + VRT IF packing **********************************************************************/ -void vrt::if_hdr_pack_$(suffix)( +void vrt::if_hdr_pack_${suffix}( boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info ){ @@ -306,29 +277,29 @@ void vrt::if_hdr_pack_$(suffix)( switch (if_packet_info.link_type) { case if_packet_info_t::LINK_TYPE_NONE: - __if_hdr_pack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); - packet_buff[0] = $(XE_MACRO)(vrt_hdr_word32); + __if_hdr_pack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32); + packet_buff[0] = ${XE_MACRO}(vrt_hdr_word32); break; case if_packet_info_t::LINK_TYPE_CHDR: { - __if_hdr_pack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); + __if_hdr_pack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32); const boost::uint32_t chdr = vrt_to_chdr(vrt_hdr_word32, if_packet_info); - packet_buff[0] = $(XE_MACRO)(chdr); + packet_buff[0] = ${XE_MACRO}(chdr); break; } case if_packet_info_t::LINK_TYPE_VRLP: - __if_hdr_pack_$(suffix)(packet_buff+2, if_packet_info, vrt_hdr_word32); + __if_hdr_pack_${suffix}(packet_buff+2, if_packet_info, vrt_hdr_word32); if_packet_info.num_header_words32 += 2; if_packet_info.num_packet_words32 += 3; - packet_buff[0] = $(XE_MACRO)(VRLP); - packet_buff[1] = $(XE_MACRO)(boost::uint32_t( + packet_buff[0] = ${XE_MACRO}(VRLP); + packet_buff[1] = ${XE_MACRO}(boost::uint32_t( (if_packet_info.num_packet_words32 & 0xfffff) | ((if_packet_info.packet_count & 0xfff) << 20) )); - packet_buff[2] = $(XE_MACRO)(vrt_hdr_word32); - packet_buff[if_packet_info.num_packet_words32-1] = $(XE_MACRO)(VEND); + packet_buff[2] = ${XE_MACRO}(vrt_hdr_word32); + packet_buff[if_packet_info.num_packet_words32-1] = ${XE_MACRO}(VEND); break; } } @@ -336,7 +307,7 @@ void vrt::if_hdr_pack_$(suffix)( /*********************************************************************** * link layer + VRT IF unpacking **********************************************************************/ -void vrt::if_hdr_unpack_$(suffix)( +void vrt::if_hdr_unpack_${suffix}( const boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info ){ @@ -344,16 +315,16 @@ void vrt::if_hdr_unpack_$(suffix)( switch (if_packet_info.link_type) { case if_packet_info_t::LINK_TYPE_NONE: - vrt_hdr_word32 = $(XE_MACRO)(packet_buff[0]); - __if_hdr_unpack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); + vrt_hdr_word32 = ${XE_MACRO}(packet_buff[0]); + __if_hdr_unpack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32); break; case if_packet_info_t::LINK_TYPE_CHDR: { - const boost::uint32_t chdr = $(XE_MACRO)(packet_buff[0]); + const boost::uint32_t chdr = ${XE_MACRO}(packet_buff[0]); vrt_hdr_word32 = chdr_to_vrt(chdr, if_packet_info); size_t packet_count = if_packet_info.packet_count; - __if_hdr_unpack_$(suffix)(packet_buff, if_packet_info, vrt_hdr_word32); + __if_hdr_unpack_${suffix}(packet_buff, if_packet_info, vrt_hdr_word32); if_packet_info.num_payload_bytes -= (~chdr + 1) & 0x3; if_packet_info.packet_count = packet_count; break; @@ -361,12 +332,12 @@ void vrt::if_hdr_unpack_$(suffix)( case if_packet_info_t::LINK_TYPE_VRLP: { - if ($(XE_MACRO)(packet_buff[0]) != VRLP) throw uhd::value_error("bad vrl header VRLP"); - const boost::uint32_t vrl_hdr = $(XE_MACRO)(packet_buff[1]); - vrt_hdr_word32 = $(XE_MACRO)(packet_buff[2]); + if (${XE_MACRO}(packet_buff[0]) != VRLP) throw uhd::value_error("bad vrl header VRLP"); + const boost::uint32_t vrl_hdr = ${XE_MACRO}(packet_buff[1]); + vrt_hdr_word32 = ${XE_MACRO}(packet_buff[2]); if (if_packet_info.num_packet_words32 < (vrl_hdr & 0xfffff)) throw uhd::value_error("bad vrl header or packet fragment"); - if ($(XE_MACRO)(packet_buff[(vrl_hdr & 0xfffff)-1]) != VEND) throw uhd::value_error("bad vrl trailer VEND"); - __if_hdr_unpack_$(suffix)(packet_buff+2, if_packet_info, vrt_hdr_word32); + if (${XE_MACRO}(packet_buff[(vrl_hdr & 0xfffff)-1]) != VEND) throw uhd::value_error("bad vrl trailer VEND"); + __if_hdr_unpack_${suffix}(packet_buff+2, if_packet_info, vrt_hdr_word32); if_packet_info.num_header_words32 += 2; //add vrl header if_packet_info.packet_count = (vrl_hdr >> 20) & 0xfff; break; @@ -375,16 +346,16 @@ void vrt::if_hdr_unpack_$(suffix)( } ######################################################################## -#end def +</%def> ######################################################################## -$gen_code("BE_MACRO", "be") -$gen_code("LE_MACRO", "le") +${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)) + from mako.template import Template + return Template(_tmpl_text).render(**kwargs) if __name__ == '__main__': import sys diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index ae33cc036..f92117a9e 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -71,7 +71,18 @@ private: timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; - libusb_handle_events_timeout(context, &tv); + int ret = libusb_handle_events_timeout(context, &tv); + switch (ret) + { + case LIBUSB_SUCCESS: + case LIBUSB_ERROR_TIMEOUT: + break; + case LIBUSB_ERROR_NO_DEVICE: + throw uhd::io_error(libusb_strerror(LIBUSB_ERROR_NO_DEVICE)); + default: + UHD_MSG(error) << __FUNCTION__ << ": " << libusb_strerror((libusb_error)ret) << std::endl; + break; + } } }; @@ -251,6 +262,21 @@ public: _claimed.push_back(interface); } + void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) + { + int ret; + ret = libusb_clear_halt(this->get(), recv_endpoint | 0x80); + UHD_LOG << "usb device handle: recv endpoint clear: " << libusb_error_name(ret) << std::endl; + ret = libusb_clear_halt(this->get(), send_endpoint | 0x00); + UHD_LOG << "usb device handle: send endpoint clear: " << libusb_error_name(ret) << std::endl; + } + + void reset_device(void) + { + int ret = libusb_reset_device(this->get()); + UHD_LOG << "usb device handle: dev Reset: " << libusb_error_name(ret) << std::endl; + } + private: libusb::device::sptr _dev; //always keep a reference to device libusb_device_handle *_handle; @@ -345,15 +371,21 @@ libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){ std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list( boost::uint16_t vid, boost::uint16_t pid ){ - std::vector<usb_device_handle::sptr> handles; + return usb_device_handle::get_device_list(std::vector<usb_device_handle::vid_pid_pair_t>(1,usb_device_handle::vid_pid_pair_t(vid,pid))); +} +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list) +{ + std::vector<usb_device_handle::sptr> handles; libusb::device_list::sptr dev_list = libusb::device_list::make(); - for (size_t i = 0; i < dev_list->size(); i++){ - usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); - if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){ - handles.push_back(handle); - } + for(size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter) + { + for (size_t i = 0; i < dev_list->size(); i++){ + usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); + if (handle->get_vendor_id() == vid_pid_pair_list[iter].first and handle->get_product_id() == vid_pid_pair_list[iter].second){ + handles.push_back(handle); + } + } } - return handles; } diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index b00946614..2ff1291d9 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -24,6 +24,29 @@ #include <uhd/transport/usb_device_handle.hpp> #include <libusb.h> +//! Define LIBUSB_CALL when its missing (non-windows) +#ifndef LIBUSB_CALL + #define LIBUSB_CALL +#endif /*LIBUSB_CALL*/ + +//! libusb_handle_events_timeout_completed is only in newer API +#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED + #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ + libusb_handle_events_timeout(ctx, tx) +#endif /* HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED */ + +//! libusb_error_name is only in newer API +#ifndef HAVE_LIBUSB_ERROR_NAME + #define libusb_error_name(code) \ + str(boost::format("LIBUSB_ERROR_CODE %d") % code) +#endif /* HAVE_LIBUSB_ERROR_NAME */ + +//! libusb_strerror is only in newer API +#ifndef HAVE_LIBUSB_STRERROR + #define libusb_strerror(code) \ + libusb_error_name(code) +#endif /* HAVE_LIBUSB_STRERROR */ + /*********************************************************************** * Libusb object oriented smart pointer wrappers: * The following wrappers provide allocation and automatic deallocation @@ -135,6 +158,10 @@ namespace libusb { * Control interface: 0 */ virtual void claim_interface(int) = 0; + + virtual void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) = 0; + + virtual void reset_device(void) = 0; }; /*! diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 1ac02d16f..b67b36d0a 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -43,23 +43,6 @@ using namespace uhd::transport; static const size_t DEFAULT_NUM_XFERS = 16; //num xfers static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes -//! Define LIBUSB_CALL when its missing (non-windows) -#ifndef LIBUSB_CALL - #define LIBUSB_CALL -#endif /*LIBUSB_CALL*/ - -//! libusb_handle_events_timeout_completed is only in newer API -#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED - #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ - libusb_handle_events_timeout(ctx, tx) -#endif - -//! libusb_error_name is only in newer API -#ifndef HAVE_LIBUSB_ERROR_NAME - #define libusb_error_name(code) \ - str(boost::format("LIBUSB_ERROR_CODE %d") % code) -#endif - //! type for sharing the release queue with managed buffers class libusb_zero_copy_mb; typedef boost::shared_ptr<bounded_buffer<libusb_zero_copy_mb *> > mb_queue_sptr; @@ -155,7 +138,8 @@ public: result.is_recv = _is_recv; #endif const int ret = libusb_submit_transfer(_lut); - if (ret != 0) throw uhd::runtime_error(str(boost::format( + if (ret != LIBUSB_SUCCESS) + throw uhd::usb_error(ret, str(boost::format( "usb %s submit failed: %s") % _name % libusb_error_name(ret))); } @@ -164,8 +148,9 @@ public: { if (wait_for_completion(timeout)) { - if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::runtime_error(str(boost::format( - "usb %s transfer status: %d") % _name % int(result.status))); + if (result.status != LIBUSB_TRANSFER_COMPLETED) + throw uhd::runtime_error(str(boost::format("usb %s transfer status: %d") + % _name % libusb_error_name(result.status))); result.completed = 0; return make(reinterpret_cast<buffer_type *>(this), _lut->buffer, (_is_recv)? result.actual_length : _frame_size); } @@ -219,7 +204,8 @@ public: _num_frames(num_frames), _frame_size(frame_size), _buffer_pool(buffer_pool::make(_num_frames, _frame_size)), - _enqueued(_num_frames), _released(_num_frames) + _enqueued(_num_frames), _released(_num_frames), + _status(STATUS_RUNNING) { const bool is_recv = (endpoint & 0x80) != 0; const std::string name = str(boost::format("%s%d") % ((is_recv)? "rx" : "tx") % int(endpoint & 0x7f)); @@ -304,18 +290,24 @@ public: UHD_INLINE typename buffer_type::sptr get_buff(double timeout) { typename buffer_type::sptr buff; - libusb_zero_copy_mb *front = NULL; - boost::mutex::scoped_lock lock(_mutex); + + if (_status == STATUS_ERROR) + return buff; + + // Serialize access to buffers + boost::mutex::scoped_lock get_buff_lock(_get_buff_mutex); + + boost::mutex::scoped_lock queue_lock(_queue_mutex); if (_enqueued.empty()) { - _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6))); + _buff_ready_cond.timed_wait(queue_lock, boost::posix_time::microseconds(long(timeout*1e6))); } if (_enqueued.empty()) return buff; - front = _enqueued.front(); + libusb_zero_copy_mb *front = _enqueued.front(); - lock.unlock(); + queue_lock.unlock(); buff = front->get_new<buffer_type>(timeout); - lock.lock(); + queue_lock.lock(); if (buff) _enqueued.pop_front(); this->submit_what_we_can(); @@ -333,28 +325,39 @@ private: buffer_pool::sptr _buffer_pool; std::vector<boost::shared_ptr<libusb_zero_copy_mb> > _mb_pool; - boost::mutex _mutex; - boost::condition_variable _cond; + boost::mutex _queue_mutex; + boost::condition_variable _buff_ready_cond; + boost::mutex _get_buff_mutex; //! why 2 queues? there is room in the future to have > N buffers but only N in flight boost::circular_buffer<libusb_zero_copy_mb *> _enqueued, _released; + enum {STATUS_RUNNING, STATUS_ERROR} _status; + void enqueue_buffer(libusb_zero_copy_mb *mb) { - boost::mutex::scoped_lock l(_mutex); + boost::mutex::scoped_lock l(_queue_mutex); _released.push_back(mb); this->submit_what_we_can(); - l.unlock(); - _cond.notify_one(); + _buff_ready_cond.notify_one(); } void submit_what_we_can(void) { + if (_status == STATUS_ERROR) + return; while (not _released.empty() and not _enqueued.full()) { - _released.front()->submit(); - _enqueued.push_back(_released.front()); - _released.pop_front(); + try { + _released.front()->submit(); + _enqueued.push_back(_released.front()); + _released.pop_front(); + } + catch (uhd::usb_error& e) + { + _status = STATUS_ERROR; + throw e; + } } } diff --git a/host/lib/transport/nirio/lvbitx/process-lvbitx.py b/host/lib/transport/nirio/lvbitx/process-lvbitx.py index ab9625608..7887c3997 100755 --- a/host/lib/transport/nirio/lvbitx/process-lvbitx.py +++ b/host/lib/transport/nirio/lvbitx/process-lvbitx.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -# Copyright 2013-2014 Ettus Research LLC +# Copyright 2013-2015 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 @@ -35,7 +35,7 @@ parser.add_option("--output-src-path", type="string", dest="output_src_path", he # Args if (len(args) < 1): - print 'ERROR: Please specify the input LVBITX file name' + print('ERROR: Please specify the input LVBITX file name') sys.exit(1) lvbitx_filename = args[0] @@ -44,16 +44,16 @@ autogen_src_path = os.path.abspath(options.output_src_path) if (options.output_s class_name = os.path.splitext(os.path.basename(input_filename))[0] if (not os.path.isfile(input_filename)): - print 'ERROR: FPGA File ' + input_filename + ' could not be accessed or is not a file.' + print('ERROR: FPGA File ' + input_filename + ' could not be accessed or is not a file.') sys.exit(1) if (options.merge_bin is not None and not os.path.isfile(os.path.abspath(options.merge_bin))): - print 'ERROR: FPGA Bin File ' + options.merge_bin + ' could not be accessed or is not a file.' + print('ERROR: FPGA Bin File ' + options.merge_bin + ' could not be accessed or is not a file.') sys.exit(1) if (not os.path.exists(autogen_src_path)): - print 'ERROR: Output path ' + autogen_src_path + ' could not be accessed.' + print('ERROR: Output path ' + autogen_src_path + ' could not be accessed.') sys.exit(1) if (options.output_lvbitx_path is not None and input_filename == os.path.join(autogen_src_path, class_name + '.lvbitx')): - print 'ERROR: Input and output LVBITX files were the same. Choose a difference input file or output path.' + print('ERROR: Input and output LVBITX files were the same. Choose a difference input file or output path.') sys.exit(1) # Get XML Tree Node @@ -122,7 +122,7 @@ def map_SubType_to_ScalarType(SubType): elif SubType == 'U64': ScalarType = 'RIO_SCALAR_TYPE_UQ' else: - print 'ERROR: No corresponding nirio_scalar_type_t value for SubType ' + SubType + ' .' + print('ERROR: No corresponding nirio_scalar_type_t value for SubType ' + SubType + ' .') sys.exit(1) return ScalarType; @@ -187,7 +187,7 @@ codegen_transform['lvbitx_signature'] = str.upper(root.find('SignatureRegister') # Write BIN file bitstream = base64.b64decode(root.find('Bitstream').text) if (options.output_lvbitx_path is not None and hashlib.md5(bitstream).hexdigest() != root.find('BitstreamMD5').text): - print 'ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.' + print('ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.') sys.exit(1) if (options.output_bin): fpga_bin_file = open(os.path.join(options.output_lvbitx_path, class_name + '.bin'), 'w') diff --git a/host/lib/transport/nirio/nirio_driver_iface_linux.cpp b/host/lib/transport/nirio/nirio_driver_iface_linux.cpp index 4afc1579f..4d983de17 100644 --- a/host/lib/transport/nirio/nirio_driver_iface_linux.cpp +++ b/host/lib/transport/nirio/nirio_driver_iface_linux.cpp @@ -25,16 +25,6 @@ namespace nirio_driver_iface { -struct nirio_ioctl_block_t -{ - uint64_t in_buf; - uint64_t out_buf; - uint32_t in_buf_len; - uint32_t out_buf_len; - uint32_t bytes_returned; - uint32_t padding; -}; - nirio_status rio_open( const std::string& device_path, rio_dev_handle_t& device_handle) diff --git a/host/lib/transport/nirio/niriok_proxy_impl_v1.cpp b/host/lib/transport/nirio/niriok_proxy_impl_v1.cpp index f0ffe2ffc..444e98f1b 100644 --- a/host/lib/transport/nirio/niriok_proxy_impl_v1.cpp +++ b/host/lib/transport/nirio/niriok_proxy_impl_v1.cpp @@ -26,8 +26,397 @@ #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif +// CTL_CODE macro for non-win OSes +#ifndef UHD_PLATFORM_WIN32 + #define CTL_CODE(a,controlCode,b,c) (controlCode) +#endif + +const uint32_t NIRIO_IOCTL_BASE = 0x800; + +const uint32_t NIRIO_IOCTL_SYNCOP = + CTL_CODE(FILE_DEVICE_UNKNOWN, + NIRIO_IOCTL_BASE + 4, + METHOD_OUT_DIRECT, + FILE_READ_DATA | FILE_WRITE_DATA); + ///< The synchronous operation code. Note: We + /// must use METHOD_OUT_DIRECT on the syncOp() + /// IOCTL to ensure the contents of the output + /// block are available in the kernel. + +const uint32_t NIRIO_IOCTL_GET_IFACE_NUM = + CTL_CODE(FILE_DEVICE_UNKNOWN, + NIRIO_IOCTL_BASE + 6, + METHOD_BUFFERED, + FILE_READ_DATA); ///< Get the interface number for a device + +const uint32_t NIRIO_IOCTL_GET_SESSION = + CTL_CODE(FILE_DEVICE_UNKNOWN, + NIRIO_IOCTL_BASE + 8, + METHOD_BUFFERED, + FILE_READ_ACCESS); ///< Gets a previously opened session to a device + +const uint32_t NIRIO_IOCTL_POST_OPEN = + CTL_CODE(FILE_DEVICE_UNKNOWN, + NIRIO_IOCTL_BASE + 9, + METHOD_BUFFERED, + FILE_READ_ACCESS); ///< Called after opening a session + +const uint32_t NIRIO_IOCTL_PRE_CLOSE = + CTL_CODE(FILE_DEVICE_UNKNOWN, + NIRIO_IOCTL_BASE + 10, + METHOD_BUFFERED, + FILE_READ_ACCESS); ///< Called before closing a session + namespace uhd { namespace niusrprio { + // ------------------------------- + // Function Codes: defined as integers rather than enums because they + // are going to be carried accross boundaries so size matters + + struct NIRIO_FUNC + { + static const uint32_t GET32 = 0x00000001; + static const uint32_t SET32 = 0x00000002; + static const uint32_t SET_DRIVER_CONFIG = 0x00000007; + static const uint32_t FIFO = 0x00000008; + static const uint32_t IO = 0x0000000A; + static const uint32_t FIFO_STOP_ALL = 0x0000000C; + static const uint32_t ADD_RESOURCE = 0x0000000D; + static const uint32_t GET_STRING = 0x0000000E; + static const uint32_t SET_STRING = 0x0000000F; + static const uint32_t DOWNLOAD = 0x00000013; + static const uint32_t RESET = 0x00000014; + }; + + struct NIRIO_RESOURCE + { + static const uint32_t INPUT_FIFO = 0xD0000001; + static const uint32_t OUTPUT_FIFO = 0xD0000002; + }; + + struct NIRIO_FIFO + { + static const uint32_t CONFIGURE = 0x80000001; + static const uint32_t START = 0x80000002; + static const uint32_t STOP = 0x80000003; + static const uint32_t READ = 0x80000004; + static const uint32_t WRITE = 0x80000005; + static const uint32_t WAIT = 0x80000006; + static const uint32_t GRANT = 0x80000007; + }; + + struct NIRIO_IO + { + static const uint32_t POKE64 = 0xA0000005; + static const uint32_t POKE32 = 0xA0000006; + static const uint32_t POKE16 = 0xA0000007; + static const uint32_t POKE8 = 0xA0000008; + static const uint32_t PEEK64 = 0xA0000009; + static const uint32_t PEEK32 = 0xA000000A; + static const uint32_t PEEK16 = 0xA000000B; + static const uint32_t PEEK8 = 0xA000000C; + static const uint32_t READ_BLOCK = 0xA000000D; + static const uint32_t WRITE_BLOCK = 0xA000000E; + static const uint32_t GET_IO_WINDOW = 0xA000000F; + static const uint32_t GET_IO_WINDOW_SIZE = 0xA0000010; + }; + + struct nirio_ioctl_packet_t { + nirio_ioctl_packet_t(void* const _outBuf, const uint32_t _outSize, const int32_t _statusCode) + { + outBuf._64BitField = 0; + outBuf.pointer = _outBuf; + outSize = _outSize; + statusCode = _statusCode; + }; + + union { + void* pointer; + uint64_t _64BitField; + } outBuf; + + uint32_t outSize; + int32_t statusCode; + }; + + struct nirio_syncop_in_params_t + { + uint32_t function; + uint32_t subfunction; + + union + { + struct + { + uint32_t attribute; + uint32_t value; + } attribute32; + + struct + { + uint32_t attribute; + uint64_t value; + } attribute64; + + struct + { + uint32_t attribute; + } attributeStr; + + struct + { + uint32_t attribute; + } download; + + union + { + struct + { + uint32_t reserved_field_0_0_0; + } reserved_field_0_0; + struct + { + uint32_t reserved_field_0_1_0; + uint32_t reserved_field_0_1_1; + } reserved_field_0_1; + struct + { + uint32_t reserved_field_0_2_0; + } reserved_field_0_2; + } reserved_field_0; + + union + { + struct + { + uint32_t channel; + uint32_t baseAddress; + uint32_t depthInSamples; + uint32_t version; + } fifo; + struct + { + uint32_t channel; + uint32_t baseAddress; + uint32_t depthInSamples; + uint32_t version; + uint32_t scalarType; + uint32_t bitWidth; + } fifoWithDataType; + struct + { + uint64_t rangeBaseAddress; + uint32_t rangeSizeInBytes; + uint32_t rangeAttribute; + } atomic; // obsolete + } add; + + struct + { + uint32_t channel; + + union + { + struct + { + uint32_t requestedDepth; + uint8_t requiresActuals; + } config; + struct + { + uint32_t timeout; + } read; + struct + { + uint32_t timeout; + uint32_t scalarType; + uint32_t bitWidth; + } readWithDataType; + struct + { + uint32_t timeout; + } write; + struct + { + uint32_t timeout; + uint32_t scalarType; + uint32_t bitWidth; + } writeWithDataType; + struct + { + uint32_t elementsRequested; + uint32_t scalarType; + uint32_t bitWidth; + uint32_t timeout; + uint8_t output; + } wait; + struct + { + uint32_t elements; + } grant; + } op; + } fifo; + + struct + { + uint64_t reserved_field_1_0; + uint32_t reserved_field_1_1; + uint32_t reserved_field_1_2; + } reserved_field_1; // Obsolete + + struct + { + uint32_t offset; + union + { + uint64_t value64; + uint32_t value32; + uint16_t value16; + uint8_t value8; + } value; + union + { + uint32_t sizeToMap; + } memoryMappedIoWindow; + } io; + + struct + { + uint32_t reserved_field_2_0; + uint32_t reserved_field_2_1; + } reserved_field_2; + + struct + { + uint32_t reserved_field_3_0; + } reserved_field_3; + + union + { + struct + { + uint32_t reserved_field_4_0; + int32_t reserved_field_4_1; + } wait; + } reserved_field_4; + + } params; + + uint32_t inbufByteLen; + + union + { + const void* pointer; + uint64_t _64BitField; + } inbuf; + }; + + static inline void init_syncop_in_params(nirio_syncop_in_params_t& param, const void* const buf, const uint32_t len) + { + param.inbuf._64BitField = 0; + param.inbuf.pointer = buf; + param.inbufByteLen = len; + } + + struct nirio_syncop_out_params_t + { + union + { + struct + { + uint32_t value; + } attribute32; + + struct + { + uint64_t value; + } attribute64; + + union + { + struct + { + uint32_t reserved_field_0_0; + } enable; + } reserved_field_0; + + struct + { + union + { + struct + { + uint32_t actualDepth; + uint32_t actualSize; + } config; + struct + { + uint32_t numberRead; + uint32_t numberRemaining; + } read; + struct + { + uint32_t numberRemaining; + } write; + struct + { + union + { + void* pointer; + uint64_t _64BitField; + } elements; + } wait; + } op; + } fifo; + + struct + { + union + { + union + { + uint64_t value64; + uint32_t value32; + uint16_t value16; + uint8_t value8; + } value; + union + { + void* memoryMappedAddress; + uint64_t _64BitField; + } memoryMappedIoWindow; + union + { + uint32_t size; + } memoryMappedIoWindowSize; + }; + } io; + + uint32_t stringLength; + + struct + { + uint32_t reserved_field_1_0; + } reserved_field_1; + + } params; + + uint32_t outbufByteLen; + + union + { + void* pointer; + uint64_t _64BitField; + } outbuf; + }; + + static inline void init_syncop_out_params(nirio_syncop_out_params_t& param, void* buf, uint32_t len) + { + param.outbuf._64BitField = 0; + param.outbuf.pointer = buf; + param.outbufByteLen = len; + } + //------------------------------------------------------- // niriok_proxy_impl_v1 //------------------------------------------------------- @@ -55,11 +444,11 @@ namespace uhd { namespace niusrprio interface_path, _device_handle), status); if (nirio_status_not_fatal(status)) { nirio_status_chain(nirio_driver_iface::rio_ioctl(_device_handle, - nirio_driver_iface::NIRIO_IOCTL_POST_OPEN, + NIRIO_IOCTL_POST_OPEN, NULL, 0, NULL, 0), status); nirio_ioctl_packet_t out(&_interface_num, sizeof(_interface_num), 0); nirio_status_chain(nirio_driver_iface::rio_ioctl(_device_handle, - nirio_driver_iface::NIRIO_IOCTL_GET_IFACE_NUM, + NIRIO_IOCTL_GET_IFACE_NUM, NULL, 0, &out, sizeof(out)), status); @@ -83,7 +472,7 @@ namespace uhd { namespace niusrprio if(nirio_driver_iface::rio_isopen(_device_handle)) { nirio_driver_iface::rio_ioctl( - _device_handle, nirio_driver_iface::NIRIO_IOCTL_PRE_CLOSE, NULL, 0, NULL, 0); + _device_handle, NIRIO_IOCTL_PRE_CLOSE, NULL, 0, NULL, 0); nirio_driver_iface::rio_close(_device_handle); } } @@ -100,18 +489,6 @@ namespace uhd { namespace niusrprio return sync_operation(&in, sizeof(in), &out, sizeof(out)); } - nirio_status niriok_proxy_impl_v1::get_cached_session( - uint32_t& session) - { - READER_LOCK - - nirio_ioctl_packet_t out(&session, sizeof(session), 0); - return nirio_driver_iface::rio_ioctl(_device_handle, - nirio_driver_iface::NIRIO_IOCTL_GET_SESSION, - NULL, 0, - &out, sizeof(out)); - } - nirio_status niriok_proxy_impl_v1::get_version( nirio_version_t type, uint32_t& major, @@ -150,7 +527,7 @@ namespace uhd { namespace niusrprio nirio_ioctl_packet_t out(readBuffer, readBufferLength, 0); nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle, - nirio_driver_iface::NIRIO_IOCTL_SYNCOP, + NIRIO_IOCTL_SYNCOP, writeBuffer, writeBufferLength, &out, sizeof(out)); if (nirio_status_fatal(ioctl_status)) return ioctl_status; @@ -282,14 +659,14 @@ namespace uhd { namespace niusrprio nirio_status niriok_proxy_impl_v1::add_fifo_resource(const nirio_fifo_info_t& fifo_info) { - niriok_proxy_impl_v1::nirio_syncop_in_params_t in = {}; - niriok_proxy_impl_v1::nirio_syncop_out_params_t out = {}; + nirio_syncop_in_params_t in = {}; + nirio_syncop_out_params_t out = {}; - in.function = niriok_proxy_impl_v1::NIRIO_FUNC::ADD_RESOURCE; + in.function = NIRIO_FUNC::ADD_RESOURCE; if (fifo_info.direction == OUTPUT_FIFO) - in.subfunction = niriok_proxy_impl_v1::NIRIO_RESOURCE::OUTPUT_FIFO; + in.subfunction = NIRIO_RESOURCE::OUTPUT_FIFO; else - in.subfunction = niriok_proxy_impl_v1::NIRIO_RESOURCE::INPUT_FIFO; + in.subfunction = NIRIO_RESOURCE::INPUT_FIFO; in.params.add.fifoWithDataType.channel = fifo_info.channel; in.params.add.fifoWithDataType.baseAddress = fifo_info.base_addr; @@ -307,7 +684,7 @@ namespace uhd { namespace niusrprio nirio_syncop_in_params_t in = {}; nirio_syncop_out_params_t out = {}; - in.function = niriok_proxy_impl_v1::NIRIO_FUNC::SET_DRIVER_CONFIG; + in.function = NIRIO_FUNC::SET_DRIVER_CONFIG; in.subfunction = 0; return sync_operation(&in, sizeof(in), &out, sizeof(out)); diff --git a/host/lib/transport/nirio/niriok_proxy_impl_v2.cpp b/host/lib/transport/nirio/niriok_proxy_impl_v2.cpp index 748db5cf8..f75de01e1 100644 --- a/host/lib/transport/nirio/niriok_proxy_impl_v2.cpp +++ b/host/lib/transport/nirio/niriok_proxy_impl_v2.cpp @@ -27,9 +27,263 @@ #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif +#define IOCTL_TRANSPORT_GET32 IOCTL(0, 0, IOCTL_ACCESS_READ) +#define IOCTL_TRANSPORT_SET32 IOCTL(0, 1, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_GET_STRING IOCTL(0, 2, IOCTL_ACCESS_READ) +#define IOCTL_TRANSPORT_SET_STRING IOCTL(0, 3, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_RESET IOCTL(1, 1, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_ADD_INPUT_FIFO_RESOURCE IOCTL(2, 0, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_ADD_OUTPUT_FIFO_RESOURCE IOCTL(2, 1, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_SET_DEVICE_CONFIG IOCTL(2, 3, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_FIFO_CONFIG IOCTL(4, 0, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_FIFO_START IOCTL(4, 1, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_FIFO_STOP IOCTL(4, 2, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_FIFO_READ IOCTL(4, 3, IOCTL_ACCESS_READ) +#define IOCTL_TRANSPORT_FIFO_WRITE IOCTL(4, 4, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_FIFO_WAIT IOCTL(4, 5, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_FIFO_GRANT IOCTL(4, 6, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_FIFO_STOP_ALL IOCTL(4, 7, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_PEEK64 IOCTL(5, 2, IOCTL_ACCESS_READ) +#define IOCTL_TRANSPORT_PEEK32 IOCTL(5, 3, IOCTL_ACCESS_READ) +#define IOCTL_TRANSPORT_POKE64 IOCTL(5, 6, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_POKE32 IOCTL(5, 7, IOCTL_ACCESS_WRITE) +#define IOCTL_TRANSPORT_POST_OPEN IOCTL(8, 0, IOCTL_ACCESS_ANY) +#define IOCTL_TRANSPORT_PRE_CLOSE IOCTL(8, 1, IOCTL_ACCESS_ANY) + namespace uhd { namespace niusrprio { //------------------------------------------------------- + // ioctl param typedefs + //------------------------------------------------------- + typedef struct { + nirio_scalar_type_t scalarType; + nirio_u32_t bitWidth; + nirio_i32_t integerWordLength; + } nirio_fifo_data_type_t; + + typedef struct in_transport_get32 + { + nirio_device_attribute32_t attribute; + int32_t status; + } in_transport_get32_t; + typedef struct out_transport_get32 + { + uint32_t retVal__; + int32_t status; + } out_transport_get32_t; + typedef struct in_transport_set32 + { + nirio_device_attribute32_t attribute; + uint32_t value; + int32_t status; + } in_transport_set32_t; + typedef struct out_transport_set32 + { + int32_t status; + } out_transport_set32_t; + typedef struct out_transport_get_string + { + uint32_t stringLen; + int32_t status; + } out_transport_get_string_t; + typedef struct out_transport_set_string + { + int32_t status; + } out_transport_set_string_t; + typedef struct in_transport_reset + { + int32_t status; + } in_transport_reset_t; + typedef struct out_transport_reset + { + int32_t status; + } out_transport_reset_t; + typedef struct in_transport_add_input_fifo_resource + { + uint32_t channel; + uint32_t baseAddress; + uint32_t depthInSamples; + nirio_fifo_data_type_t dataType; + uint32_t version; + int32_t status; + } in_transport_add_input_fifo_resource_t; + typedef struct out_transport_addInputFifo_resource + { + int32_t status; + } out_transport_add_input_fifo_resource_t; + typedef struct in_transport_addOutputFifo_resource + { + uint32_t channel; + uint32_t baseAddress; + uint32_t depthInSamples; + nirio_fifo_data_type_t dataType; + uint32_t version; + int32_t status; + } in_transport_add_output_fifo_resource_t; + typedef struct out_transport_addOutputFifo_resource + { + int32_t status; + } out_transport_add_output_fifo_resource_t; + typedef struct in_transport_setDevice_config + { + uint32_t attribute; + int32_t status; + } in_transport_set_device_config_t; + typedef struct out_transport_setDevice_config + { + int32_t status; + } out_transport_set_device_config_t; + typedef struct in_transport_fifo_config + { + uint32_t channel; + aligned_uint64_t requestedDepth; + int32_t status; + } in_transport_fifo_config_t; + typedef struct out_transport_fifo_config + { + aligned_uint64_t actualDepth; + aligned_uint64_t actualSize; + int32_t status; + } out_transport_fifo_config_t; + typedef struct in_transport_fifo_start + { + uint32_t channel; + int32_t status; + } in_transport_fifo_start_t; + typedef struct out_transport_fifo_start + { + int32_t status; + } out_transport_fifo_start_t; + typedef struct in_transport_fifo_stop + { + uint32_t channel; + int32_t status; + } in_transport_fifo_stop_t; + typedef struct out_transport_fifo_stop + { + int32_t status; + } out_transport_fifo_stop_t; + typedef struct in_transport_fifo_read + { + uint32_t channel; + aligned_uint64_t buf; + uint32_t numberElements; + nirio_fifo_data_type_t dataType; + uint32_t timeout; + int32_t status; + } in_transport_fifo_read_t; + typedef struct out_transport_fifo_read + { + uint32_t read; + uint32_t remaining; + int32_t status; + } out_transport_fifo_read_t; + typedef struct in_transport_fifo_write + { + uint32_t channel; + aligned_uint64_t buf; + uint32_t numberElements; + nirio_fifo_data_type_t dataType; + uint32_t timeout; + int32_t status; + } in_transport_fifo_write_t; + typedef struct out_transport_fifo_write + { + uint32_t remaining; + int32_t status; + } out_transport_fifo_write_t; + typedef struct in_transport_fifo_wait + { + uint32_t channel; + aligned_uint64_t elementsRequested; + nirio_fifo_data_type_t dataType; + bool output; + uint32_t timeout; + int32_t status; + } in_transport_fifo_wait_t; + typedef struct out_transport_fifo_wait + { + aligned_uint64_t elements; + aligned_uint64_t elementsAcquired; + aligned_uint64_t elementsRemaining; + int32_t status; + } out_transport_fifo_wait_t; + typedef struct in_transport_fifo_grant + { + uint32_t channel; + aligned_uint64_t elements; + int32_t status; + } in_transport_fifo_grant_t; + typedef struct out_transport_fifo_grant + { + int32_t status; + } out_transport_fifo_grant_t; + typedef struct in_transport_fifoStop_all + { + int32_t status; + } in_transport_fifo_stop_all_t; + typedef struct out_transport_fifoStop_all + { + int32_t status; + } out_transport_fifo_stop_all_t; + typedef struct in_transport_peek64 + { + uint32_t offset; + int32_t status; + } in_transport_peek64_t; + typedef struct out_transport_peek64 + { + aligned_uint64_t retVal__; + int32_t status; + } out_transport_peek64_t; + typedef struct in_transport_peek32 + { + uint32_t offset; + int32_t status; + } in_transport_peek32_t; + typedef struct out_transport_peek32 + { + uint32_t retVal__; + int32_t status; + } out_transport_peek32_t; + typedef struct in_transport_poke64 + { + uint32_t offset; + aligned_uint64_t value; + int32_t status; + } in_transport_poke64_t; + typedef struct out_transport_poke64 + { + int32_t status; + } out_transport_poke64_t; + typedef struct in_transport_poke32 + { + uint32_t offset; + uint32_t value; + int32_t status; + } in_transport_poke32_t; + typedef struct out_transport_poke32 + { + int32_t status; + } out_transport_poke32_t; + typedef struct in_transport_post_open + { + int32_t status; + } in_transport_post_open_t; + typedef struct out_transport_post_open + { + int32_t status; + } out_transport_post_open_t; + typedef struct in_transport_pre_close + { + int32_t status; + } in_transport_pre_close_t; + typedef struct out_transport_pre_close + { + int32_t status; + } out_transport_pre_close_t; + + //------------------------------------------------------- // niriok_proxy_impl_v2 //------------------------------------------------------- niriok_proxy_impl_v2::niriok_proxy_impl_v2() @@ -110,18 +364,6 @@ namespace uhd { namespace niusrprio return out.status; } - nirio_status niriok_proxy_impl_v2::get_cached_session( - uint32_t& session) - { - READER_LOCK - - nirio_ioctl_packet_t out(&session, sizeof(session), 0); - return nirio_driver_iface::rio_ioctl(_device_handle, - nirio_driver_iface::NIRIO_IOCTL_GET_SESSION, - NULL, 0, - &out, sizeof(out)); - } - nirio_status niriok_proxy_impl_v2::get_version( nirio_version_t type, uint32_t& major, @@ -580,7 +822,7 @@ namespace uhd { namespace niusrprio out_transport_fifo_read_t out = {}; in.channel = channel; - in.buf = reinterpret_cast<tAlignedU64>(buffer); + in.buf = reinterpret_cast<aligned_uint64_t>(buffer); in.numberElements = elements_to_read; in.dataType.scalarType = map_int_to_scalar_type(scalar_type); in.dataType.bitWidth = bit_width; @@ -620,7 +862,7 @@ namespace uhd { namespace niusrprio out_transport_fifo_write_t out = {}; in.channel = channel; - in.buf = reinterpret_cast<tAlignedU64>(buffer); + in.buf = reinterpret_cast<aligned_uint64_t>(buffer); in.numberElements = elements_to_write; in.dataType.scalarType = map_int_to_scalar_type(scalar_type); in.dataType.bitWidth = bit_width; diff --git a/host/lib/transport/nirio/rpc/rpc_client.cpp b/host/lib/transport/nirio/rpc/rpc_client.cpp index cf8e9c1a9..bbaf9f235 100644 --- a/host/lib/transport/nirio/rpc/rpc_client.cpp +++ b/host/lib/transport/nirio/rpc/rpc_client.cpp @@ -52,7 +52,7 @@ rpc_client::rpc_client ( //- address_configured: Only return addresses if a non-loopback address is configured for the system. //- numeric_host: No name resolution should be attempted for host //- numeric_service: No name resolution should be attempted for service - tcp::resolver::query::flags query_flags; + tcp::resolver::query::flags query_flags(tcp::resolver::query::passive); tcp::resolver::query query(tcp::v4(), server, port, query_flags); tcp::resolver::iterator iterator = resolver.resolve(query); diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 5c84327a4..0f1f7ff3a 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -147,7 +147,7 @@ public: */ void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff, const bool flush = false){ if (flush){ - while (get_buff(0.0)); + while (get_buff(0.0)) {}; } _props.at(xport_chan).get_buff = get_buff; } @@ -560,6 +560,11 @@ private: _props[index].handle_overflow(); curr_info.metadata = metadata; UHD_MSG(fastpath) << "O"; + + // Not sending flow control would cause timeouts due to source flow control locking up + if(_props[index].handle_flowctrl) { + _props[index].handle_flowctrl(next_info[index].ifpi.packet_count); + } } return; diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index adc7d5585..70fb5b552 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -87,7 +87,10 @@ public: if (wait_for_recv_ready(_sock_fd, timeout)){ _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0); - UHD_ASSERT_THROW(_len > 0); // TODO: Handle case of recv error + if (_len == 0) + throw uhd::io_error("socket closed"); + if (_len < 0) + throw uhd::io_error(str(boost::format("recv error on socket: %s") % strerror(errno))); index++; //advances the caller's buffer return make(this, _mem, size_t(_len)); } @@ -126,6 +129,10 @@ public: boost::this_thread::sleep(boost::posix_time::microseconds(1)); continue; //try to send again } + if (ret == -1) + { + throw uhd::io_error(str(boost::format("send error on socket: %s") % strerror(errno))); + } UHD_ASSERT_THROW(ret == ssize_t(size())); } _claimer.release(); |