summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/docs/usrp2.rst49
-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/usrp2/fw_common.h9
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp57
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp1
6 files changed, 189 insertions, 43 deletions
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/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/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 */