diff options
Diffstat (limited to 'host')
| -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 | 
15 files changed, 553 insertions, 48 deletions
| 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 */ | 
