From d93a2cf7c904964ba7f41f4d654b18e099df7451 Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Thu, 3 Mar 2011 19:26:32 -0800
Subject: usrp2: work on mtu discovery

added echo routine to the firmware and discovery routine to host

the implementation is integrated into the factory function and appears to work on linux
---
 host/lib/usrp/usrp2/fw_common.h     |  6 +++
 host/lib/usrp/usrp2/mboard_impl.cpp |  8 ++--
 host/lib/usrp/usrp2/usrp2_impl.cpp  | 96 ++++++++++++++++++++++++++++++++-----
 3 files changed, 95 insertions(+), 15 deletions(-)

(limited to 'host/lib/usrp')

diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 6eb047454..68c49cafc 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -89,6 +89,9 @@ typedef enum{
     USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO = 'v',
     USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE = 'V',
 
+    USRP2_CTRL_ID_HOLLER_AT_ME_BRO = 'l',
+    USRP2_CTRL_ID_HOLLER_BACK_DUDE = 'L',
+
     USRP2_CTRL_ID_PEACE_OUT = '~'
 
 } usrp2_ctrl_id_t;
@@ -133,6 +136,9 @@ typedef struct{
             uint8_t bytes;
             uint8_t data[20];
         } uart_args;
+        struct {
+            uint32_t len;
+        } echo_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 5cb4e4d34..0a6fefca6 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -62,25 +62,25 @@ usrp2_mboard_impl::usrp2_mboard_impl(
 ):
     _index(index), _device(device),
     _iface(usrp2_iface::make(udp_simple::make_connected(
-        device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT)
+        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
     )))
 {
     //construct transports for dsp and async errors
     std::cout << "Making transport for DSP0..." << std::endl;
     device.dsp_xports.push_back(udp_zero_copy::make(
-        device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_DSP0_PORT), device_addr
+        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_addr
     ));
     init_xport(device.dsp_xports.back());
 
     std::cout << "Making transport for DSP1..." << std::endl;
     device.dsp_xports.push_back(udp_zero_copy::make(
-        device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_DSP1_PORT), device_addr
+        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_addr
     ));
     init_xport(device.dsp_xports.back());
 
     std::cout << "Making transport for ERR0..." << std::endl;
     device.err_xports.push_back(udp_zero_copy::make(
-        device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_ERR0_PORT), device_addr_t()
+        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t()
     ));
     init_xport(device.err_xports.back());
 
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 651e9a89b..164253f96 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -143,7 +143,75 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){
 /***********************************************************************
  * Make
  **********************************************************************/
-static device::sptr usrp2_make(const device_addr_t &_device_addr){
+static device::sptr usrp2_make(const device_addr_t &device_addr){
+    return device::sptr(new usrp2_impl(device_addr));
+}
+
+UHD_STATIC_BLOCK(register_usrp2_device){
+    device::register_device(&usrp2_find, &usrp2_make);
+}
+
+/***********************************************************************
+ * MTU Discovery
+ **********************************************************************/
+struct mtu_result_t{
+    size_t recv_mtu, send_mtu;
+};
+
+static mtu_result_t determine_mtu(const std::string &addr){
+    udp_simple::sptr udp_sock = udp_simple::make_connected(
+        addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
+    );
+
+    mtu_result_t mtu;
+    boost::uint8_t buffer[2000]; //FIXME use real FPGA buffer maximum
+    usrp2_ctrl_data_t *ctrl_data = reinterpret_cast<usrp2_ctrl_data_t *>(buffer);
+    static const double echo_timeout = 0.010; //10 ms
+
+    size_t min_recv_mtu = sizeof(usrp2_ctrl_data_t), max_recv_mtu = sizeof(buffer);
+    size_t min_send_mtu = sizeof(usrp2_ctrl_data_t), max_send_mtu = sizeof(buffer);
+
+    while (min_recv_mtu + 4 < max_recv_mtu){
+
+        mtu.recv_mtu = (max_recv_mtu + min_recv_mtu)/2 & ~(4-1);
+        //std::cout << "recv_mtu " << mtu.recv_mtu << std::endl;
+
+        ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO);
+        ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM);
+        ctrl_data->data.echo_args.len = htonl(mtu.recv_mtu);
+        udp_sock->send(boost::asio::buffer(buffer, sizeof(usrp2_ctrl_data_t)));
+
+        size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout);
+
+        if (len >= mtu.recv_mtu) min_recv_mtu = mtu.recv_mtu;
+        else                     max_recv_mtu = mtu.recv_mtu;
+
+    }
+
+    while (min_send_mtu + 4 < max_send_mtu){
+
+        mtu.send_mtu = (max_send_mtu + min_send_mtu)/2 & ~(4-1);
+        //std::cout << "send_mtu " << mtu.send_mtu << std::endl;
+
+        ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO);
+        ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM);
+        ctrl_data->data.echo_args.len = htonl(sizeof(usrp2_ctrl_data_t));
+        udp_sock->send(boost::asio::buffer(buffer, mtu.send_mtu));
+
+        size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout);
+        if (len >= sizeof(usrp2_ctrl_data_t)) len = ntohl(ctrl_data->data.echo_args.len);
+
+        if (len >= mtu.send_mtu) min_send_mtu = mtu.send_mtu;
+        else                     max_send_mtu = mtu.send_mtu;
+    }
+
+    return mtu;
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
     device_addr_t device_addr = _device_addr;
 
     //setup the dsp transport hints (default to a large recv buff)
@@ -157,18 +225,24 @@ static device::sptr usrp2_make(const device_addr_t &_device_addr){
         #endif
     }
 
-    return device::sptr(new usrp2_impl(device_addr));
-}
+    device_addrs_t device_args = separate_device_addr(device_addr);
 
-UHD_STATIC_BLOCK(register_usrp2_device){
-    device::register_device(&usrp2_find, &usrp2_make);
-}
+    //calculate the minimum send and recv mtu of all devices
+    mtu_result_t mtu = determine_mtu(device_args[0]["addr"]);
+    for (size_t i = 1; i < device_args.size(); i++){
+        mtu_result_t mtu_i = determine_mtu(device_args[i]["addr"]);
+        mtu.recv_mtu = std::min(mtu.recv_mtu, mtu_i.recv_mtu);
+        mtu.send_mtu = std::min(mtu.send_mtu, mtu_i.send_mtu);
+    }
 
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_impl::usrp2_impl(const device_addr_t &device_addr){
-    device_addrs_t device_args = separate_device_addr(device_addr);
+    std::cout << "mtu recv bytes " << mtu.recv_mtu << std::endl;
+    std::cout << "mtu send bytes " << mtu.send_mtu << std::endl;
+
+    //use the discovered mtu if not specified by the user
+    if (not device_addr.has_key("recv_frame_size"))
+        device_addr["recv_frame_size"] = boost::lexical_cast<std::string>(mtu.recv_mtu);
+    if (not device_addr.has_key("send_frame_size"))
+        device_addr["send_frame_size"] = boost::lexical_cast<std::string>(mtu.send_mtu);
 
     //setup rx otw type
     _rx_otw_type.width = 16;
-- 
cgit v1.2.3