diff options
| -rw-r--r-- | firmware/zpu/apps/txrx_uhd.c | 35 | ||||
| -rw-r--r-- | firmware/zpu/lib/eth_addrs.c | 132 | ||||
| -rw-r--r-- | firmware/zpu/lib/ethernet.h | 21 | ||||
| -rw-r--r-- | firmware/zpu/lib/net_common.c | 28 | ||||
| -rw-r--r-- | firmware/zpu/lib/net_common.h | 5 | ||||
| -rw-r--r-- | firmware/zpu/usrp2p/u2p_init.c | 3 | ||||
| -rw-r--r-- | host/docs/usrp2.rst | 49 | ||||
| -rw-r--r-- | host/lib/usrp/mboard_eeprom.cpp | 77 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 9 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 57 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 1 | 
11 files changed, 287 insertions, 130 deletions
| diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c index 9daf441e2..a4bfce0ec 100644 --- a/firmware/zpu/apps/txrx_uhd.c +++ b/firmware/zpu/apps/txrx_uhd.c @@ -92,8 +92,35 @@ static void handle_udp_data_packet(      default: return;      } -    eth_mac_addr_t eth_mac_host; arp_cache_lookup_mac(&src.addr, ð_mac_host); -    setup_framer(eth_mac_host, *ethernet_mac_addr(), src, dst, which); +    //assume the packet destination is the packet source +    //the arp cache lookup should never fail for this case +    const struct socket_address src_addr = dst; +    struct socket_address dst_addr = src; +    eth_mac_addr_t eth_mac_dst; +    arp_cache_lookup_mac(&dst_addr.addr, ð_mac_dst); + +    //however, if this control packet has an alternative destination... +    if (payload_len >= sizeof(usrp2_stream_ctrl_t)){ + +        //parse the destination ip addr and udp port from the payload +        const usrp2_stream_ctrl_t *stream_ctrl = (const usrp2_stream_ctrl_t *)payload; +        dst_addr.addr.addr = stream_ctrl->ip_addr; +        dst_addr.port = (uint16_t)stream_ctrl->udp_port; +        struct ip_addr ip_dest = dst_addr.addr; + +        //are we in the subnet? if not use the gateway +        const uint32_t subnet_mask = get_subnet()->addr; +        const bool in_subnet = ((get_ip_addr()->addr & subnet_mask) == (ip_dest.addr & subnet_mask)); +        if (!in_subnet) ip_dest = *get_gateway(); + +        //lookup the host ip address with ARP (this may fail) +        const bool ok = arp_cache_lookup_mac(&ip_dest, ð_mac_dst); +        if (!ok) net_common_send_arp_request(&ip_dest); +        const uint32_t result = (ok)? 0 : ~0; +        send_udp_pkt(dst.port, src, &result, sizeof(result)); +    } + +    setup_framer(eth_mac_dst, *ethernet_mac_addr(), dst_addr, src_addr, which);  }  #define OTW_GPIO_BANK_TO_NUM(bank) \ @@ -279,6 +306,7 @@ int  main(void)  {    u2_init(); +  arp_cache_init();  #ifdef BOOTLOADER    putstr("\nUSRP N210 UDP bootloader\n");  #else @@ -294,8 +322,7 @@ main(void)    //load the production FPGA image or firmware if appropriate    do_the_bootload_thing();    //if we get here we've fallen through to safe firmware -  set_default_mac_addr(); -  set_default_ip_addr(); +  eth_addrs_set_default();  #endif    print_mac_addr(ethernet_mac_addr()); newline(); diff --git a/firmware/zpu/lib/eth_addrs.c b/firmware/zpu/lib/eth_addrs.c index c45ce7559..6d3347cf3 100644 --- a/firmware/zpu/lib/eth_addrs.c +++ b/firmware/zpu/lib/eth_addrs.c @@ -1,5 +1,5 @@  /* - * Copyright 2010-2011 Ettus Research LLC + * Copyright 2010-2012 Ettus Research LLC   * Copyright 2007 Free Software Foundation, Inc.   *   * This program is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@  #include "memory_map.h"  #include "nonstdio.h"  #include <stdbool.h> +#include <string.h>  #include "i2c.h"  #include "usrp2/fw_common.h" @@ -37,104 +38,69 @@ unprogrammed(const void *t, size_t len)    return all_ones | all_zeros;  } -//////////////////// MAC Addr Stuff /////////////////////// +typedef struct{ +    eth_mac_addr_t mac_addr; +    struct ip_addr ip_addr; +    struct ip_addr gateway; +    struct ip_addr subnet; +} eth_addrs_t; -static bool src_mac_addr_initialized = false; +static bool eth_addrs_initialized = false; -static const eth_mac_addr_t default_mac_addr = {{ -    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff -  }}; +static const eth_addrs_t default_eth_addrs = { +    .mac_addr = {{0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff}}, +    .ip_addr = {(192 << 24 | 168 << 16 | 10  << 8  | 2 << 0)}, +    .gateway = {(192 << 24 | 168 << 16 | 10  << 8  | 1 << 0)}, +    .subnet  = {(255 << 24 | 255 << 16 | 255 << 8  | 0 << 0)}, +}; -static eth_mac_addr_t src_mac_addr = {{ -    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff -  }}; -   -void set_default_mac_addr(void) -{ -    src_mac_addr_initialized = true; -    src_mac_addr = default_mac_addr; -} +static eth_addrs_t current_eth_addrs; -const eth_mac_addr_t * -ethernet_mac_addr(void) -{ -  if (!src_mac_addr_initialized){    // fetch from eeprom -    src_mac_addr_initialized = true; +static void eth_addrs_init(void){ +    if (eth_addrs_initialized) return; +    eth_addrs_initialized = true; -    // if we're simulating, don't read the EEPROM model, it's REALLY slow -    if (hwconfig_simulation_p()) -      return &src_mac_addr; - -    eth_mac_addr_t tmp; -    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); -    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ -      // use the default +    #define eth_addrs_init_x(addr, x){ \ +        const bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, addr, ¤t_eth_addrs.x, sizeof(current_eth_addrs.x)); \ +        if (!ok || unprogrammed(¤t_eth_addrs.x, sizeof(current_eth_addrs.x))){ \ +            memcpy(¤t_eth_addrs.x, &default_eth_addrs.x, sizeof(current_eth_addrs.x)); \ +        } \      } -    else -      src_mac_addr = tmp; -  } -  return &src_mac_addr; -} +    eth_addrs_init_x(USRP2_EE_MBOARD_MAC_ADDR, mac_addr); +    eth_addrs_init_x(USRP2_EE_MBOARD_IP_ADDR,  ip_addr); +    eth_addrs_init_x(USRP2_EE_MBOARD_GATEWAY,  gateway); +    eth_addrs_init_x(USRP2_EE_MBOARD_SUBNET,   subnet); -bool -ethernet_set_mac_addr(const eth_mac_addr_t *t) -{ -  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); -  if (ok){ -    src_mac_addr = *t; -    src_mac_addr_initialized = true; -    //eth_mac_set_addr(t); //this breaks the link -  } - -  return ok;  } -//////////////////// IP Addr Stuff /////////////////////// - -static bool src_ip_addr_initialized = false; - -static const struct ip_addr default_ip_addr = { -    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) -}; - -static struct ip_addr src_ip_addr = { -    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) -}; - -void set_default_ip_addr(void) -{ -    src_ip_addr_initialized = true; -    src_ip_addr = default_ip_addr; +const eth_mac_addr_t *ethernet_mac_addr(void){ +    eth_addrs_init(); +    return ¤t_eth_addrs.mac_addr;  } -const struct ip_addr *get_ip_addr(void) -{ -  if (!src_ip_addr_initialized){    // fetch from eeprom -    src_ip_addr_initialized = true; - -    // if we're simulating, don't read the EEPROM model, it's REALLY slow -    if (hwconfig_simulation_p()) -      return &src_ip_addr; +const struct ip_addr *get_ip_addr(void){ +    eth_addrs_init(); +    return ¤t_eth_addrs.ip_addr; +} -    struct ip_addr tmp; -    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); -    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ -      // use the default -    } -    else -      src_ip_addr = tmp; -  } +const struct ip_addr *get_subnet(void){ +    eth_addrs_init(); +    return ¤t_eth_addrs.subnet; +} -  return &src_ip_addr; +const struct ip_addr *get_gateway(void){ +    eth_addrs_init(); +    return ¤t_eth_addrs.gateway;  }  bool set_ip_addr(const struct ip_addr *t){ -  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); -  if (ok){ -    src_ip_addr = *t; -    src_ip_addr_initialized = true; -  } +    const bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +    if (ok) current_eth_addrs.ip_addr = *t; +    return ok; +} -  return ok; +void eth_addrs_set_default(void){ +    eth_addrs_initialized = true; +    memcpy(¤t_eth_addrs, &default_eth_addrs, sizeof(default_eth_addrs));  } diff --git a/firmware/zpu/lib/ethernet.h b/firmware/zpu/lib/ethernet.h index 52b297349..b5b08cb8c 100644 --- a/firmware/zpu/lib/ethernet.h +++ b/firmware/zpu/lib/ethernet.h @@ -1,5 +1,5 @@ -/* -*- c -*- */  /* + * Copyright 2010-2012 Ettus Research LLC   * Copyright 2007 Free Software Foundation, Inc.   *   * This program is free software: you can redistribute it and/or modify @@ -44,27 +44,28 @@ void ethernet_register_link_changed_callback(ethernet_link_changed_callback_t cb   */  const eth_mac_addr_t *ethernet_mac_addr(void); -/*!set mac addr to default*/ -void set_default_mac_addr(void); -  /*! - * \brief write mac address to eeprom and begin using it + * \returns IP address   */ -bool ethernet_set_mac_addr(const eth_mac_addr_t *t); +const struct ip_addr *get_ip_addr(void);  /*! - * \returns IP address + * \returns gateway address   */ -const struct ip_addr *get_ip_addr(void); +const struct ip_addr *get_gateway(void); -/*!set ip addr to default*/ -void set_default_ip_addr(void); +/*! + * \returns subnet address + */ +const struct ip_addr *get_subnet(void);  /*!   * \brief write ip address to eeprom and begin using it   */  bool set_ip_addr(const struct ip_addr *t); +//! Apply default settings to eth addrs +void eth_addrs_set_default(void);  /*   * \brief read RMON regs and return error mask diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c index 42e365393..9b75006d3 100644 --- a/firmware/zpu/lib/net_common.c +++ b/firmware/zpu/lib/net_common.c @@ -1,5 +1,5 @@  /* - * Copyright 2009-2011 Ettus Research LLC + * Copyright 2009-2012 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 @@ -374,6 +374,22 @@ send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac)    send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0);  } +void net_common_send_arp_request(const struct ip_addr *addr){ +    struct arp_eth_ipv4 req _AL4; +    req.ar_hrd = ARPHRD_ETHER; +    req.ar_pro = ETHERTYPE_IPV4; +    req.ar_hln = sizeof(eth_mac_addr_t); +    req.ar_pln = sizeof(struct ip_addr); +    req.ar_op = ARPOP_REQUEST; +    memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); +    memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr)); +    memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t)); +    memcpy(req.ar_tip, addr, sizeof(struct ip_addr)); + +    //send the request with a broadcast ethernet mac address +    send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0); +} +  void send_gratuitous_arp(void){    struct arp_eth_ipv4 req _AL4;    req.ar_hrd = ARPHRD_ETHER; @@ -415,7 +431,15 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size)        || p->ar_hln != 6        || p->ar_pln != 4)      return; -   + +  if (p->ar_op == ARPOP_REPLY){ +    struct ip_addr ip_addr; +    memcpy(&ip_addr, p->ar_sip, sizeof(ip_addr)); +    eth_mac_addr_t mac_addr; +    memcpy(&mac_addr, p->ar_sha, sizeof(mac_addr)); +    arp_cache_update(&ip_addr, &mac_addr); +  } +    if (p->ar_op != ARPOP_REQUEST)      return; diff --git a/firmware/zpu/lib/net_common.h b/firmware/zpu/lib/net_common.h index 3cbc5c514..5e6daf689 100644 --- a/firmware/zpu/lib/net_common.h +++ b/firmware/zpu/lib/net_common.h @@ -1,5 +1,5 @@  /* - * Copyright 2009-2011 Ettus Research LLC + * Copyright 2009-2012 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 @@ -55,4 +55,7 @@ void handle_eth_packet(uint32_t *p, size_t nlines);  void send_gratuitous_arp(void); +//! Send an ARP request for the given IP address +void net_common_send_arp_request(const struct ip_addr *addr); +  #endif /* INCLUDED_NET_COMMON_H */ diff --git a/firmware/zpu/usrp2p/u2p_init.c b/firmware/zpu/usrp2p/u2p_init.c index 381987ae6..1890dd726 100644 --- a/firmware/zpu/usrp2p/u2p_init.c +++ b/firmware/zpu/usrp2p/u2p_init.c @@ -24,7 +24,6 @@ void u2p_init(void){      bool safe_fw = find_safe_booted_flag();      set_safe_booted_flag(0);      if (safe_fw) { -        set_default_ip_addr(); -        set_default_mac_addr(); +        eth_addrs_set_default();      }  } diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index d81440b07..bf42e70b9 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -315,6 +315,55 @@ the following clock configuration must be set on the slave device:      clock_config.pps_source = uhd::clock_config_t::PPS_MIMO;      usrp->set_clock_config(clock_config, slave_index); + +------------------------------------------------------------------------ +Alternative stream destination +------------------------------------------------------------------------ +It is possible to program the USRP to send RX packets to an alternative IP/UDP destination. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Set the subnet and gateway +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +To use an alternative streaming destination, +the device needs to be able to determine if the destination address +is within its subnet, and ARP appropriately. +Therefore, the user should ensure that subnet and gateway addresses +have been programmed into the device's EEPROM. + +Run the following commands: +:: + +    cd <install-path>/share/uhd/utils +    ./usrp_burn_mb_eeprom --args=<optional device args> --key=subnet --val=255.255.255.0 +    ./usrp_burn_mb_eeprom --args=<optional device args> --key=gateway --val=192.168.10.1 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Create a receive streamer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Set the stream args "addr" and "port" values to the alternative destination. +Packets will be sent to this destination when the user issues a stream command. + +:: + +    //create a receive streamer, host type does not matter +    uhd::stream_args_t stream_args("fc32"); + +    //resolvable address and port for a remote udp socket +    stream_args.args["addr"] = "192.168.10.42"; +    stream_args.args["port"] = "12345"; + +    //create the streamer +    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); + +    //issue stream command +    uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); +    stream_cmd.num_samps = total_num_samps; +    stream_cmd.stream_now = true; +    usrp->issue_stream_cmd(stream_cmd); + +**Note:** +Calling recv() on this streamer object should yield a timeout. +  ------------------------------------------------------------------------  Hardware setup notes  ------------------------------------------------------------------------ diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index 785d30296..96a0d36ce 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -84,17 +84,20 @@ static std::string uint16_bytes_to_string(const byte_vector_t &bytes){   **********************************************************************/  static const boost::uint8_t N100_EEPROM_ADDR = 0x50; -static const uhd::dict<std::string, boost::uint8_t> USRP_N100_OFFSETS = boost::assign::map_list_of -    ("hardware", 0x00) -    ("mac-addr", 0x02) -    ("ip-addr", 0x0C) -    //leave space here for other addresses (perhaps) -    ("revision", 0x12) -    ("product", 0x14) -    ("gpsdo", 0x17) -    ("serial", 0x18) -    ("name", 0x18 + SERIAL_LEN) -; +struct n100_eeprom_map{ +    boost::uint16_t hardware; +    boost::uint8_t mac_addr[6]; +    boost::uint32_t subnet; +    boost::uint32_t ip_addr; +    boost::uint16_t _pad0; +    boost::uint16_t revision; +    boost::uint16_t product; +    unsigned char _pad1; +    unsigned char gpsdo; +    unsigned char serial[SERIAL_LEN]; +    unsigned char name[NAME_MAX_LEN]; +    boost::uint32_t gateway; +};  enum n200_gpsdo_type{      N200_GPSDO_NONE = 0, @@ -105,30 +108,36 @@ enum n200_gpsdo_type{  static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){      //extract the hardware number      mb_eeprom["hardware"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["hardware"], 2) +        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware), 2)      );      //extract the revision number      mb_eeprom["revision"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["revision"], 2) +        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision), 2)      );      //extract the product code      mb_eeprom["product"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["product"], 2) +        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product), 2)      );      //extract the addresses      mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(iface.read_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"], 6 +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr), 6      )).to_string();      boost::asio::ip::address_v4::bytes_type ip_addr_bytes; -    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes); +    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), 4), ip_addr_bytes);      mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); +    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), 4), ip_addr_bytes); +    mb_eeprom["subnet"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), 4), ip_addr_bytes); +    mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); +      //gpsdo capabilities -    boost::uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], 1).at(0); +    boost::uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), 1).at(0);      switch(n200_gpsdo_type(gpsdo_byte)){      case N200_GPSDO_INTERNAL: mb_eeprom["gpsdo"] = "internal"; break;      case N200_GPSDO_ONBOARD: mb_eeprom["gpsdo"] = "onboard"; break; @@ -137,12 +146,12 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){      //extract the serial      mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], SERIAL_LEN +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial), SERIAL_LEN      ));      //extract the name      mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], NAME_MAX_LEN +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name), NAME_MAX_LEN      ));      //Empty serial correction: use the mac address to determine serial. @@ -158,32 +167,44 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){  static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){      //parse the revision number      if (mb_eeprom.has_key("hardware")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["hardware"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware),          string_to_uint16_bytes(mb_eeprom["hardware"])      );      //parse the revision number      if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["revision"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision),          string_to_uint16_bytes(mb_eeprom["revision"])      );      //parse the product code      if (mb_eeprom.has_key("product")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["product"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product),          string_to_uint16_bytes(mb_eeprom["product"])      );      //store the addresses      if (mb_eeprom.has_key("mac-addr")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr),          mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes()      );      if (mb_eeprom.has_key("ip-addr")){          byte_vector_t ip_addr_bytes(4);          byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes); -        iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], ip_addr_bytes); +        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), ip_addr_bytes); +    } + +    if (mb_eeprom.has_key("subnet")){ +        byte_vector_t ip_addr_bytes(4); +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"]).to_bytes(), ip_addr_bytes); +        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), ip_addr_bytes); +    } + +    if (mb_eeprom.has_key("gateway")){ +        byte_vector_t ip_addr_bytes(4); +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); +        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), ip_addr_bytes);      }      //gpsdo capabilities @@ -191,18 +212,18 @@ static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){          boost::uint8_t gpsdo_byte = N200_GPSDO_NONE;          if (mb_eeprom["gpsdo"] == "internal") gpsdo_byte = N200_GPSDO_INTERNAL;          if (mb_eeprom["gpsdo"] == "onboard") gpsdo_byte = N200_GPSDO_ONBOARD; -        iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], byte_vector_t(1, gpsdo_byte)); +        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), byte_vector_t(1, gpsdo_byte));      }      //store the serial      if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial),          string_to_bytes(mb_eeprom["serial"], SERIAL_LEN)      );      //store the name      if (mb_eeprom.has_key("name")) iface.write_eeprom( -        N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], +        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name),          string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN)      );  } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 0babf7445..2add74c47 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -37,6 +37,13 @@ extern "C" {  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 +typedef struct{ +    uint32_t sequence; +    uint32_t vrt_hdr; +    uint32_t ip_addr; +    uint32_t udp_port; +} usrp2_stream_ctrl_t; +  // udp ports for the usrp2 communication  // Dynamic and/or private ports: 49152-65535  #define USRP2_UDP_CTRL_PORT 49152 @@ -65,6 +72,8 @@ extern "C" {  ////////////////////////////////////////////////////////////////////////  #define USRP2_EE_MBOARD_REV      0x00 //2 bytes, little-endian (historic, don't blame me)  #define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_GATEWAY  0x38 //uint32, big-endian +#define USRP2_EE_MBOARD_SUBNET   0x08 //uint32, big-endian  #define USRP2_EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian  #define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7 diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index d32ffb62c..ea4aa716c 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -21,6 +21,7 @@  #include "../../transport/super_send_packet_handler.hpp"  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include "fw_common.h"  #include <uhd/utils/log.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/utils/tasks.hpp> @@ -31,6 +32,7 @@  #include <boost/thread/thread.hpp>  #include <boost/format.hpp>  #include <boost/bind.hpp> +#include <boost/asio.hpp>  #include <boost/thread/mutex.hpp>  #include <boost/make_shared.hpp>  #include <iostream> @@ -361,6 +363,60 @@ bool usrp2_impl::recv_async_msg(  }  /*********************************************************************** + * Stream destination programmer + **********************************************************************/ +void usrp2_impl::program_stream_dest( +    zero_copy_if::sptr &xport, const uhd::stream_args_t &args +){ +    //perform an initial flush of transport +    while (xport->get_recv_buff(0.0)){} + +    //program the stream command +    usrp2_stream_ctrl_t stream_ctrl = usrp2_stream_ctrl_t(); +    stream_ctrl.sequence = uhd::htonx(boost::uint32_t(0 /* don't care seq num */)); +    stream_ctrl.vrt_hdr = uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)); + +    //user has provided an alternative address and port for destination +    if (args.args.has_key("addr") and args.args.has_key("port")){ +        UHD_MSG(status) << boost::format( +            "Programming streaming destination for custom address.\n" +            "IPv4 Address: %s, UDP Port: %s\n" +        ) % args.args["addr"] % args.args["port"] << std::endl; + +        asio::io_service io_service; +        asio::ip::udp::resolver resolver(io_service); +        asio::ip::udp::resolver::query query(asio::ip::udp::v4(), args.args["addr"], args.args["port"]); +        asio::ip::udp::endpoint endpoint = *resolver.resolve(query); +        stream_ctrl.ip_addr = uhd::htonx(boost::uint32_t(endpoint.address().to_v4().to_ulong())); +        stream_ctrl.udp_port = uhd::htonx(boost::uint32_t(endpoint.port())); + +        for (size_t i = 0; i < 3; i++){ +            UHD_MSG(status) << "ARP attempt " << i << std::endl; +            managed_send_buffer::sptr send_buff = xport->get_send_buff(); +            std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl)); +            send_buff->commit(sizeof(stream_ctrl)); +            boost::this_thread::sleep(boost::posix_time::milliseconds(300)); +            managed_recv_buffer::sptr recv_buff = xport->get_recv_buff(0.0); +            if (recv_buff and recv_buff->size() >= sizeof(boost::uint32_t)){ +                const boost::uint32_t result = uhd::ntohx(recv_buff->cast<const boost::uint32_t *>()[0]); +                if (result == 0){ +                    UHD_MSG(status) << "Success! " << std::endl; +                    return; +                } +            } +        } +        throw uhd::runtime_error("Device failed to ARP when programming alternative streaming destination."); +    } + +    else{ +        //send the partial stream control without destination +        managed_send_buffer::sptr send_buff = xport->get_send_buff(); +        std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl)); +        send_buff->commit(sizeof(stream_ctrl)/2); +    } +} + +/***********************************************************************   * Receive streamer   **********************************************************************/  rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){ @@ -406,6 +462,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){                  const size_t dsp = chan + _mbc[mb].rx_chan_occ - num_chan_so_far;                  _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this                  _mbc[mb].rx_dsps[dsp]->setup(args); +                this->program_stream_dest(_mbc[mb].rx_dsp_xports[dsp], args);                  my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(                      &zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1                  ), true /*flush*/); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e5065c02d..6053c3890 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -129,6 +129,7 @@ private:      double set_tx_dsp_freq(const std::string &, const double);      uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);      void update_clock_source(const std::string &, const std::string &); +    void program_stream_dest(uhd::transport::zero_copy_if::sptr &, const uhd::stream_args_t &);  };  #endif /* INCLUDED_USRP2_IMPL_HPP */ | 
