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 | ||||
-rwxr-xr-x | host/cmake/debian/preinst.in | 2 | ||||
-rwxr-xr-x | host/cmake/debian/prerm.in | 1 | ||||
-rwxr-xr-x | host/cmake/redhat/pre_install.in | 2 | ||||
-rwxr-xr-x | host/cmake/redhat/pre_uninstall.in | 1 | ||||
-rw-r--r-- | host/docs/usrp2.rst | 49 | ||||
-rw-r--r-- | host/examples/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/examples/transport_hammer.cpp | 348 | ||||
-rw-r--r-- | host/lib/usrp/common/fx2_ctrl.cpp | 39 | ||||
-rw-r--r-- | host/lib/usrp/mboard_eeprom.cpp | 77 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/soft_time_ctrl.cpp | 6 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/soft_time_ctrl.hpp | 5 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.cpp | 3 | ||||
-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 |
21 files changed, 675 insertions, 150 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/cmake/debian/preinst.in b/host/cmake/debian/preinst.in index 9e8e50b90..71246b7e7 100755 --- a/host/cmake/debian/preinst.in +++ b/host/cmake/debian/preinst.in @@ -17,5 +17,5 @@ # if [ "$1" = "install" ]; then - echo + echo 'Installing UHD.' fi diff --git a/host/cmake/debian/prerm.in b/host/cmake/debian/prerm.in index 30ce41963..dfe491767 100755 --- a/host/cmake/debian/prerm.in +++ b/host/cmake/debian/prerm.in @@ -17,6 +17,7 @@ # if [ "$1" = "remove" ]; then + echo 'Uninstalling UHD.' rm /etc/udev/rules.d/uhd-usrp.rules udevadm control --reload-rules fi diff --git a/host/cmake/redhat/pre_install.in b/host/cmake/redhat/pre_install.in index b611fb381..e62d603ab 100755 --- a/host/cmake/redhat/pre_install.in +++ b/host/cmake/redhat/pre_install.in @@ -15,3 +15,5 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # + +echo 'Installing UHD.' diff --git a/host/cmake/redhat/pre_uninstall.in b/host/cmake/redhat/pre_uninstall.in index f1faa36ce..806da7f7c 100755 --- a/host/cmake/redhat/pre_uninstall.in +++ b/host/cmake/redhat/pre_uninstall.in @@ -16,5 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +echo 'Uninstalling UHD.' rm /etc/udev/rules.d/uhd-usrp.rules udevadm control --reload-rules diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 8a2782982..d70a08cd7 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/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 3c9a3880a..b41d53d11 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -27,6 +27,7 @@ SET(example_sources rx_timed_samples.cpp test_messages.cpp test_pps_input.cpp + transport_hammer.cpp tx_bursts.cpp tx_samples_from_file.cpp tx_timed_samples.cpp diff --git a/host/examples/transport_hammer.cpp b/host/examples/transport_hammer.cpp new file mode 100644 index 000000000..8e588e2fb --- /dev/null +++ b/host/examples/transport_hammer.cpp @@ -0,0 +1,348 @@ +// +// Copyright 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 +// 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/utils/thread_priority.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp/multi_usrp.hpp> +#include <boost/program_options.hpp> +#include <boost/thread/thread.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> +#include <time.h> + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args; + double delay; + size_t total_num_samps; + double rate; + int step; + int rand_begin; + int rand_end; + size_t samp_begin; + size_t samp_end; + float ampl; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args") + ("delay", po::value<double>(&delay)->default_value(0.0), "delay between sample jumps") + ("step", po::value<int>(&step)->default_value(1), "delta between number of samples collected/sent") + ("samp_begin", po::value<size_t>(&samp_begin)->default_value(1), "Beginning number of samples") + ("samp_end", po::value<size_t>(&samp_end)->default_value(32768), "End number of samples") + ("rate", po::value<double>(&rate)->default_value(3.125e6), "rate of incoming samples") + ("tx", "specify to use TX samples instead of RX samples") + ("rx", "specify to use RX samples (already default") + ("rand_vals", "specify to continuously use random numbers of samples") + ("rand_begin", po::value<int>(&rand_begin)->default_value(0), "specify minimum value outputted by random number generator") + ("rand_end", po::value<int>(&rand_end)->default_value(2000), "specify maximum value outputting by random number generator") + ("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of each sample") + ("verbose", "Enables verbosity") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD Transport Hammer - %s") % desc << std::endl; + return ~0; + } + + bool use_tx = vm.count("tx") > 0; + bool rand_vals = vm.count("rand_vals") > 0; + bool verbose = vm.count("verbose") > 0; + + if (use_tx) + { + //create a usrp device + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); + std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; + + //set the tx sample rate + std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; + usrp->set_tx_rate(rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl; + usrp->set_time_now(uhd::time_spec_t(0.0)); + + //create a transmit streamer + uhd::stream_args_t stream_args("fc32"); //complex floats + uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); + + //allocate buffer with data to send + std::vector<std::complex<float> > buff(tx_stream->get_max_num_samps(), std::complex<float>(ampl, ampl)); + + //setup metadata for the first packet + uhd::tx_metadata_t md; + md.start_of_burst = false; + md.end_of_burst = false; + md.has_time_spec = false; + //md.time_spec = uhd::time_spec_t(seconds_in_future); + + + if(rand_vals){ + + std::srand((unsigned int) time(NULL)); + + while(true){ + size_t total_num_samps = (rand() % (rand_end - rand_begin)) + rand_begin; + size_t num_acc_samps = 0; + float timeout = 0; + + std::cout << "----------------------------------------" << std::endl; + std::cout << boost::format("About to send %u samples.") % total_num_samps << std::endl << std::endl; + + usrp->set_time_now(uhd::time_spec_t(0.0)); + + while(num_acc_samps < total_num_samps){ + size_t samps_to_send = std::min(total_num_samps - num_acc_samps, buff.size()); + if(verbose) std::cout << boost::format("Sent %u samples.") % samps_to_send << std::endl; + + + //send a single packet + size_t num_tx_samps = tx_stream->send(&buff.front(), samps_to_send, md, timeout); + + if(num_tx_samps < samps_to_send) std::cerr << "Send timeout..." << std::endl; + //if(verbose) std::cout << boost::format("Sent packet: %u samples") % num_tx_samps << std::endl; + + num_acc_samps += num_tx_samps; + } + + md.end_of_burst = true; + tx_stream->send("", 0, md); + + if(verbose) std::cout << std::endl; + std::cout << "Waiting for async burst ACK... " << std::endl << std::flush; + uhd::async_metadata_t async_md; + bool got_async_burst_ack = false; + //loop through all messages for the ACK packet (may have underflow messages in queue) + while (not got_async_burst_ack and usrp->get_device()->recv_async_msg(async_md, timeout)){ + got_async_burst_ack = (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK); + } + std::cout << (got_async_burst_ack? "Success!" : "Failure...") << std::endl << std::endl; + + std::cout << boost::format("Successfully sent %u samples.") % total_num_samps << std::endl << "----------------------------------------" << std::endl << std::endl; + + boost::this_thread::sleep(boost::posix_time::microseconds(long(delay*1e6))); + + } + } + else{ + + float timeout = 0; + + if(verbose){ + std::cout << "About to start sending samples." << std::endl; + std::cout << boost::format("Samples will start at %u and end with %u with steps of %u.") % samp_begin % samp_end % step << std::endl; + + boost::this_thread::sleep(boost::posix_time::seconds(2)); + } + + for(int i = int(samp_begin); i <= int(samp_end); i += step){ + + std::cout << "----------------------------------------" << std::endl; + + usrp->set_time_now(uhd::time_spec_t(0.0)); + + std::cout << boost::format("About to send %u samples.") % i << std::endl; + if(verbose) std::cout << std::endl; + + size_t num_acc_samps = 0; //number of accumulated samples + total_num_samps = i; + + while(num_acc_samps < total_num_samps){ + size_t samps_to_send = std::min(total_num_samps - num_acc_samps, buff.size()); + + if(verbose) std::cout << boost::format("Sent %u samples.") % samps_to_send << std::endl; + + //send a single packet + size_t num_tx_samps = tx_stream->send( + &buff.front(), samps_to_send, md, timeout + ); + + if (num_tx_samps < samps_to_send) std::cerr << "Send timeout..." << std::endl; + + num_acc_samps += num_tx_samps; + } + + //send a mini EOB packet + md.end_of_burst = true; + tx_stream->send("", 0, md); + + std::cout << std::endl << "Waiting for async burst ACK... " << std::endl << std::flush; + uhd::async_metadata_t async_md; + bool got_async_burst_ack = false; + //loop through all messages for the ACK packet (may have underflow messages in queue) + while (not got_async_burst_ack and usrp->get_device()->recv_async_msg(async_md, timeout)){ + got_async_burst_ack = (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK); + } + std::cout << (got_async_burst_ack? "Success!" : "Failure...") << std::endl << std::endl; + + std::cout << boost::format("Successfully sent %u samples.") % i << std::endl << "----------------------------------------" << std::endl << std::endl; + + boost::this_thread::sleep(boost::posix_time::microseconds(long(delay*1e6))); + } + + //finished + std::cout << "Done!" << std::endl << std::endl; + } + + return 0; + } + else + { + //create a usrp device + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); + std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; + + //set the rx sample rate + std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl; + usrp->set_rx_rate(rate); + std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl; + + + + if(rand_vals){ + //random here + + std::srand((unsigned int) time(NULL)); + + while(true){ + total_num_samps = (rand() % (rand_end - rand_begin)) + rand_begin; + + usrp->set_time_now(uhd::time_spec_t(0.0)); + + //create a receive streamer + uhd::stream_args_t stream_args("fc32"); //complex floats + uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); + + std::cout << std::endl << "----------------------------------------" << std::endl; + std::cout << boost::format("About to receive %u samples.") % total_num_samps << std::endl << std::endl; + + 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); + + //meta-data will be filled in by recv() + uhd::rx_metadata_t md; + + //allocate buffer to receive with samples + std::vector<std::complex<float> > buff(rx_stream->get_max_num_samps()); + double timeout = 0; + + size_t num_acc_samps = 0; //number of accumulated samples + while(num_acc_samps < total_num_samps){ + //receive a single packet + size_t num_rx_samps = rx_stream->recv( + &buff.front(), buff.size(), md, timeout, true + ); + + //handle the error code + if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break; + if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ + throw std::runtime_error(str(boost::format( + "Unexpected error code 0x%x" + ) % md.error_code)); + } + if(verbose) std::cout << boost::format("Received %u samples.") % num_rx_samps << std::endl; + num_acc_samps += num_rx_samps; + } + boost::this_thread::sleep(boost::posix_time::microseconds(long(delay*1e6))); + + if (num_acc_samps < total_num_samps) std::cerr << "Receive timeout before all samples received..." << std::endl; + + if(verbose) std::cout << std::endl; + std::cout << boost::format("Successfully received %u samples.") % total_num_samps << std::endl << "----------------------------------------" << std::endl; + } + } + else{ + + if(verbose) { + std::cout << std::endl << "About to start receiving samples." << std::endl; + std::cout << boost::format("Samples will start at %u and end with %u with steps of %u.") % samp_begin % samp_end % step << std::endl << std::endl; + + boost::this_thread::sleep(boost::posix_time::seconds(2)); + } + + for(int i = int(samp_begin); i <= int(samp_end); i += step){ + + usrp->set_time_now(uhd::time_spec_t(0.0)); + + //create a receive streamer + uhd::stream_args_t stream_args("fc32"); //complex floats + uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); + + //setup streaming + std::cout << std::endl; + std::cout << "----------------------------------------" << std::endl; + std::cout << boost::format("About to receive %u samples.") % i << std::endl << std::endl; + uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); + stream_cmd.num_samps = i; + stream_cmd.stream_now = true; + usrp->issue_stream_cmd(stream_cmd); + + //meta-data will be filled in by recv() + uhd::rx_metadata_t md; + + //allocate buffer to receive with samples + std::vector<std::complex<float> > buff(rx_stream->get_max_num_samps()); + + double timeout = 0; + + size_t num_acc_samps = 0; //number of accumulated samples + while(int(num_acc_samps) < i){ + //receive a single packet + size_t num_rx_samps = rx_stream->recv( + &buff.front(), buff.size(), md, timeout, true + ); + + //handle the error code + if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break; + if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ + throw std::runtime_error(str(boost::format( + "Unexpected error code 0x%x" + ) % md.error_code)); + } + + if(verbose) std::cout << boost::format("Received %u samples.") % num_rx_samps << std::endl; + + num_acc_samps += num_rx_samps; + + } + if(verbose) std::cout << std::endl; + std::cout << boost::format("Successfully received %u samples.") % i << std::endl << "----------------------------------------" << std::endl; + + boost::this_thread::sleep(boost::posix_time::microseconds(long(delay*1e6))); + + //std::cout << boost::format("num_acc_samps=%u, i=%u") % num_acc_samps % i << std::endl; + + if (int(num_acc_samps) < i) std::cerr << "Receive timeout before all samples received..." << std::endl; + } + } + return 0; + } +} diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp index 7b8920eb1..5cc701eb0 100644 --- a/host/lib/usrp/common/fx2_ctrl.cpp +++ b/host/lib/usrp/common/fx2_ctrl.cpp @@ -411,6 +411,26 @@ public: return usrp_control_write(request, value, index, 0, 0); } + void write_eeprom( + boost::uint8_t addr, + boost::uint8_t offset, + const byte_vector_t &bytes + ){ + byte_vector_t bytes_with_cmd(bytes.size() + 1); + bytes_with_cmd[0] = offset; + std::copy(bytes.begin(), bytes.end(), &bytes_with_cmd[1]); + this->write_i2c(addr, bytes_with_cmd); + } + + byte_vector_t read_eeprom( + boost::uint8_t addr, + boost::uint8_t offset, + size_t num_bytes + ){ + this->write_i2c(addr, byte_vector_t(1, offset)); + return this->read_i2c(addr, num_bytes); + } + int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) { return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len); @@ -428,12 +448,7 @@ public: { UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); - unsigned char buff[max_i2c_data_bytes] = {}; - std::copy(bytes.begin(), bytes.end(), buff); - - int ret = this->usrp_i2c_write(addr & 0xff, - buff, - bytes.size()); + int ret = this->usrp_i2c_write(addr, (unsigned char *)&bytes.front(), bytes.size()); if (iface_debug && (ret < 0)) uhd::runtime_error("USRP: failed i2c write"); @@ -443,19 +458,13 @@ public: { UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - unsigned char buff[max_i2c_data_bytes] = {}; - int ret = this->usrp_i2c_read(addr & 0xff, - buff, - num_bytes); + byte_vector_t bytes(num_bytes); + int ret = this->usrp_i2c_read(addr, (unsigned char *)&bytes.front(), num_bytes); if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) uhd::runtime_error("USRP: failed i2c read"); - byte_vector_t out_bytes; - for (size_t i = 0; i < num_bytes; i++) - out_bytes.push_back(buff[i]); - - return out_bytes; + return bytes; } 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/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp index 90b3a92da..65bdc36d4 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-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 @@ -207,6 +207,10 @@ public: return _inline_msg_queue; } + void stop(void){ + _recv_cmd_task.reset(); + } + private: boost::mutex _update_mutex; size_t _nsamps_remaining; diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp index b92b51252..f418ec35a 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.hpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-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 @@ -67,6 +67,9 @@ public: //! Get access to a buffer of inline metadata virtual transport::bounded_buffer<rx_metadata_t> &get_inline_queue(void) = 0; + + //! Stops threads before deconstruction to avoid race conditions + virtual void stop(void) = 0; }; }} //namespace diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 607badda9..1db2efa0d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -413,8 +413,7 @@ usrp1_impl::~usrp1_impl(void){ this->enable_rx(false); this->enable_tx(false); ) - _tree.reset(); //resets counts on sptrs held in tree - _soft_time_ctrl.reset(); //stops cmd task before proceeding + _soft_time_ctrl->stop(); //stops cmd task before proceeding _io_impl.reset(); //stops vandal before other stuff gets deconstructed } 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 */ |