summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/zpu/apps/txrx_uhd.c35
-rw-r--r--firmware/zpu/lib/eth_addrs.c132
-rw-r--r--firmware/zpu/lib/ethernet.h21
-rw-r--r--firmware/zpu/lib/net_common.c28
-rw-r--r--firmware/zpu/lib/net_common.h5
-rw-r--r--firmware/zpu/usrp2p/u2p_init.c3
-rwxr-xr-xhost/cmake/debian/preinst.in2
-rwxr-xr-xhost/cmake/debian/prerm.in1
-rwxr-xr-xhost/cmake/redhat/pre_install.in2
-rwxr-xr-xhost/cmake/redhat/pre_uninstall.in1
-rw-r--r--host/docs/usrp2.rst49
-rw-r--r--host/examples/CMakeLists.txt1
-rw-r--r--host/examples/transport_hammer.cpp348
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp39
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp77
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.cpp6
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.hpp5
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp3
-rw-r--r--host/lib/usrp/usrp2/fw_common.h9
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp57
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp1
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, &eth_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, &eth_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, &eth_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, &current_eth_addrs.x, sizeof(current_eth_addrs.x)); \
+ if (!ok || unprogrammed(&current_eth_addrs.x, sizeof(current_eth_addrs.x))){ \
+ memcpy(&current_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 &current_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 &current_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 &current_eth_addrs.subnet;
+}
- return &src_ip_addr;
+const struct ip_addr *get_gateway(void){
+ eth_addrs_init();
+ return &current_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(&current_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>(&ampl)->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 */