Difference between revisions of "Getting Started with UHD and C++"

From Ettus Knowledge Base
Jump to: navigation, search
(Overview)
Line 20: Line 20:
  
 
Example code:
 
Example code:
 
    #include <uhd/utils/thread_priority.hpp>
 
    #include <uhd/utils/safe_main.hpp>
 
    #include <uhd/usrp/multi_usrp.hpp>
 
    #include <uhd/exception.hpp>
 
    #include <uhd/types/tune_request.hpp>
 
    #include <boost/program_options.hpp>
 
    #include <boost/format.hpp>
 
    #include <boost/thread.hpp>
 
    #include <iostream>
 
   
 
    int UHD_SAFE_MAIN(int argc, char *argv[]) {
 
        uhd::set_thread_priority_safe();
 
   
 
        std::string device_args("addr=192.168.10.2");
 
        std::string subdev("A:0");
 
        std::string ant("TX/RX");
 
        std::string ref("internal");
 
   
 
        double rate(1e6);
 
        double freq(915e6);
 
        double gain(10);
 
        double bw(1e6);
 
   
 
        //create a usrp device
 
        std::cout << std::endl;
 
        std::cout << boost::format("Creating the usrp device with: %s...") % device_args << std::endl;
 
        uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_args);
 
   
 
        // Lock mboard clocks
 
        std::cout << boost::format("Lock mboard clocks: %f") % ref << std::endl;
 
        usrp->set_clock_source(ref);
 
       
 
        //always select the subdevice first, the channel mapping affects the other settings
 
        std::cout << boost::format("subdev set to: %f") % subdev << std::endl;
 
        usrp->set_rx_subdev_spec(subdev);
 
        std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
 
   
 
        //set the sample rate
 
        if (rate <= 0.0) {
 
            std::cerr << "Please specify a valid sample rate" << std::endl;
 
            return ~0;
 
        }
 
   
 
        // set 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;
 
   
 
        // set freq
 
        std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq / 1e6) << std::endl;
 
        uhd::tune_request_t tune_request(freq);
 
        usrp->set_rx_freq(tune_request);
 
        std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq() / 1e6) << std::endl << std::endl;
 
   
 
        // set the rf gain
 
        std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
 
        usrp->set_rx_gain(gain);
 
        std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
 
   
 
        // set the IF filter bandwidth
 
        std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % (bw / 1e6) << std::endl;
 
        usrp->set_rx_bandwidth(bw);
 
        std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % (usrp->get_rx_bandwidth() / 1e6) << std::endl << std::endl;
 
   
 
        // set the antenna
 
        std::cout << boost::format("Setting RX Antenna: %s") % ant << std::endl;
 
        usrp->set_rx_antenna(ant);
 
        std::cout << boost::format("Actual RX Antenna: %s") % usrp->get_rx_antenna() << std::endl << std::endl;
 
   
 
        return EXIT_SUCCESS;
 
    }
 
 
 
 
Use the uhd/host/examples/init_usrp/CMakeLists.txt file as template
 
- Add the names of your C++ source files to the add_executable(...) section
 
- Put both modified CMakeLists.txt file and C++ file into an empty folder
 
- Create a “build” folder and invoke CMake the usual way:
 
 
    mkdir build
 
    cd build
 
    cmake ../
 
    make -j4
 
 
 
 
 
 
 
  
 
<syntaxhighlight lang="c++">
 
<syntaxhighlight lang="c++">
//
 
// Copyright 2011-2015 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/thread_priority.hpp>
#include <uhd/convert.hpp>
 
 
#include <uhd/utils/safe_main.hpp>
 
#include <uhd/utils/safe_main.hpp>
 
#include <uhd/usrp/multi_usrp.hpp>
 
#include <uhd/usrp/multi_usrp.hpp>
 +
#include <uhd/exception.hpp>
 +
#include <uhd/types/tune_request.hpp>
 
#include <boost/program_options.hpp>
 
#include <boost/program_options.hpp>
 
#include <boost/format.hpp>
 
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
+
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>
+
#include <boost/lexical_cast.hpp>
+
//#include <boost/atomic.hpp>
+
 
#include <iostream>
 
#include <iostream>
#include <complex>
 
#include <cstdlib>
 
  
namespace po = boost::program_options;
+
int UHD_SAFE_MAIN(int argc, char *argv[]) {
 
+
const double INIT_DELAY = 0.05;  // 50mS initial delay before transmit
+
//typedef boost::atomic<bool>  atomic_bool;
+
// We'll fake atomic bools for now, for more backward compat.
+
// This is just an example, after all.
+
typedef bool atomic_bool;
+
 
+
/***********************************************************************
+
* Test result variables
+
**********************************************************************/
+
unsigned long long num_overflows = 0;
+
unsigned long long num_underflows = 0;
+
unsigned long long num_rx_samps = 0;
+
unsigned long long num_tx_samps = 0;
+
unsigned long long num_dropped_samps = 0;
+
unsigned long long num_seq_errors = 0;
+
unsigned long long num_timeouts = 0;
+
 
+
/***********************************************************************
+
* Benchmark RX Rate
+
**********************************************************************/
+
void benchmark_rx_rate(
+
        uhd::usrp::multi_usrp::sptr usrp,
+
        const std::string &rx_cpu,
+
        uhd::rx_streamer::sptr rx_stream,
+
        bool random_nsamps,
+
        atomic_bool& burst_timer_elapsed
+
) {
+
 
     uhd::set_thread_priority_safe();
 
     uhd::set_thread_priority_safe();
  
     //print pre-test summary
+
     std::string device_args("addr=192.168.10.2");
     std::cout << boost::format(
+
     std::string subdev("A:0");
        "Testing receive rate %f Msps on %u channels"
+
     std::string ant("TX/RX");
     ) % (usrp->get_rx_rate()/1e6) % rx_stream->get_num_channels() << std::endl;
+
    std::string ref("internal");
  
     //setup variables and allocate buffer
+
     double rate(1e6);
    uhd::rx_metadata_t md;
+
     double freq(915e6);
    const size_t max_samps_per_packet = rx_stream->get_max_num_samps();
+
     double gain(10);
     std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(rx_cpu));
+
     double bw(1e6);
     std::vector<void *> buffs;
+
    for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++)
+
        buffs.push_back(&buff.front()); //same buffer for each channel
+
     bool had_an_overflow = false;
+
    uhd::time_spec_t last_time;
+
    const double rate = usrp->get_rx_rate();
+
  
     uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+
     //create a usrp device
     cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(INIT_DELAY);
+
    std::cout << std::endl;
    cmd.stream_now = (buffs.size() == 1);
+
     std::cout << boost::format("Creating the usrp device with: %s...") % device_args << std::endl;
     rx_stream->issue_stream_cmd(cmd);
+
     uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_args);
  
     const float burst_pkt_time = std::max(0.100, (2 * max_samps_per_packet/rate));
+
     // Lock mboard clocks
     float recv_timeout = burst_pkt_time + INIT_DELAY;
+
    std::cout << boost::format("Lock mboard clocks: %f") % ref << std::endl;
 +
    usrp->set_clock_source(ref);
 +
   
 +
    //always select the subdevice first, the channel mapping affects the other settings
 +
    std::cout << boost::format("subdev set to: %f") % subdev << std::endl;
 +
    usrp->set_rx_subdev_spec(subdev);
 +
     std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
  
     while (true) {
+
     //set the sample rate
        //if (burst_timer_elapsed.load(boost::memory_order_relaxed)) {
+
    if (rate <= 0.0) {
        if (burst_timer_elapsed) {
+
         std::cerr << "Please specify a valid sample rate" << std::endl;
            rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+
         return ~0;
        }
+
        if (random_nsamps) {
+
            cmd.num_samps = rand() % max_samps_per_packet;
+
            rx_stream->issue_stream_cmd(cmd);
+
        }
+
        try {
+
            num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md, recv_timeout)*rx_stream->get_num_channels();
+
            recv_timeout = burst_pkt_time;
+
        }
+
        catch (uhd::io_error &e) {
+
            std::cerr << "Caught an IO exception. " << std::endl;
+
            std::cerr << e.what() << std::endl;
+
            return;
+
        }
+
 
+
        //handle the error codes
+
        switch(md.error_code){
+
        case uhd::rx_metadata_t::ERROR_CODE_NONE:
+
            if (had_an_overflow){
+
                had_an_overflow = false;
+
                num_dropped_samps += (md.time_spec - last_time).to_ticks(rate);
+
            }
+
            break;
+
 
+
        // ERROR_CODE_OVERFLOW can indicate overflow or sequence error
+
        case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
+
            last_time = md.time_spec;
+
            had_an_overflow = true;
+
            // check out_of_sequence flag to see if it was a sequence error or overflow
+
            if (!md.out_of_sequence)
+
                num_overflows++;
+
            break;
+
 
+
         case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+
            // If we stopped the streamer, then we expect this at some point
+
            //if (burst_timer_elapsed.load(boost::memory_order_relaxed)) {
+
            if (burst_timer_elapsed) {
+
                return;
+
            }
+
            std::cerr << "Receiver error: " << md.strerror() << ", continuing..." << std::endl;
+
            num_timeouts++;
+
            break;
+
 
+
            // Otherwise, it's an error
+
         default:
+
            std::cerr << "Receiver error: " << md.strerror() << std::endl;
+
            std::cerr << "Unexpected error on recv, continuing..." << std::endl;
+
            break;
+
        }
+
 
     }
 
     }
}
 
  
/***********************************************************************
+
    // set sample rate
* Benchmark TX Rate
+
    std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate / 1e6) << std::endl;
**********************************************************************/
+
    usrp->set_rx_rate(rate);
void benchmark_tx_rate(
+
    std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate() / 1e6) << std::endl << std::endl;
        uhd::usrp::multi_usrp::sptr usrp,
+
        const std::string &tx_cpu,
+
        uhd::tx_streamer::sptr tx_stream,
+
        atomic_bool& burst_timer_elapsed,
+
        bool random_nsamps=false
+
) {
+
    uhd::set_thread_priority_safe();
+
  
     //print pre-test summary
+
     // set freq
     std::cout << boost::format(
+
     std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq / 1e6) << std::endl;
        "Testing transmit rate %f Msps on %u channels"
+
    uhd::tune_request_t tune_request(freq);
    ) % (usrp->get_tx_rate()/1e6) % tx_stream->get_num_channels() << std::endl;
+
    usrp->set_rx_freq(tune_request);
 +
    std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq() / 1e6) << std::endl << std::endl;
  
     //setup variables and allocate buffer
+
     // set the rf gain
     uhd::tx_metadata_t md;
+
     std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
    md.time_spec = usrp->get_time_now() + uhd::time_spec_t(INIT_DELAY);
+
     usrp->set_rx_gain(gain);
    md.has_time_spec = (tx_stream->get_num_channels() > 1);
+
     std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
     const size_t max_samps_per_packet = tx_stream->get_max_num_samps();
+
     std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(tx_cpu));
+
    std::vector<const void *> buffs;
+
    for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
+
        buffs.push_back(&buff.front()); //same buffer for each channel
+
    md.has_time_spec = (buffs.size() != 1);
+
  
     if (random_nsamps) {
+
     // set the IF filter bandwidth
        std::srand((unsigned int)time(NULL));
+
    std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % (bw / 1e6) << std::endl;
        //while (not burst_timer_elapsed.load(boost::memory_order_relaxed)) {
+
    usrp->set_rx_bandwidth(bw);
        while (not burst_timer_elapsed) {
+
    std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % (usrp->get_rx_bandwidth() / 1e6) << std::endl << std::endl;
            size_t total_num_samps = rand() % max_samps_per_packet;
+
            size_t num_acc_samps = 0;
+
            const float timeout = 1;
+
  
            usrp->set_time_now(uhd::time_spec_t(0.0));
+
    // set the antenna
            while(num_acc_samps < total_num_samps){
+
    std::cout << boost::format("Setting RX Antenna: %s") % ant << std::endl;
                //send a single packet
+
    usrp->set_rx_antenna(ant);
                num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md, timeout)*tx_stream->get_num_channels();
+
    std::cout << boost::format("Actual RX Antenna: %s") % usrp->get_rx_antenna() << std::endl << std::endl;
                num_acc_samps += std::min(total_num_samps-num_acc_samps, tx_stream->get_max_num_samps());
+
            }
+
        }
+
    } else {
+
        //while (not burst_timer_elapsed.load(boost::memory_order_relaxed)) {
+
        while (not burst_timer_elapsed) {
+
            num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md)*tx_stream->get_num_channels();
+
            md.has_time_spec = false;
+
        }
+
    }
+
  
     //send a mini EOB packet
+
     return EXIT_SUCCESS;
    md.end_of_burst = true;
+
    tx_stream->send(buffs, 0, md);
+
 
}
 
}
 +
</syntaxhighlight>
  
void benchmark_tx_rate_async_helper(
 
        uhd::tx_streamer::sptr tx_stream,
 
        atomic_bool& burst_timer_elapsed
 
) {
 
    //setup variables and allocate buffer
 
    uhd::async_metadata_t async_md;
 
    bool exit_flag = false;
 
  
    while (true) {
+
Use the uhd/host/examples/init_usrp/CMakeLists.txt file as template
        //if (burst_timer_elapsed.load(boost::memory_order_relaxed)) {
+
- Add the names of your C++ source files to the add_executable(...) section
        if (burst_timer_elapsed) {
+
- Put both modified CMakeLists.txt file and C++ file into an empty folder
            exit_flag = true;
+
- Create a “build” folder and invoke CMake the usual way:
        }
+
  
        if (not tx_stream->recv_async_msg(async_md)) {
+
    mkdir build
            if (exit_flag == true)
+
    cd build
                return;
+
    cmake ../
            continue;
+
    make -j4
        }
+
  
        //handle the error codes
 
        switch(async_md.event_code){
 
        case uhd::async_metadata_t::EVENT_CODE_BURST_ACK:
 
            return;
 
  
        case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW:
 
        case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET:
 
            num_underflows++;
 
            break;
 
  
        case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR:
 
        case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST:
 
            num_seq_errors++;
 
            break;
 
  
        default:
 
            std::cerr << "Event code: " << async_md.event_code << std::endl;
 
            std::cerr << "Unexpected event on async recv, continuing..." << std::endl;
 
            break;
 
        }
 
    }
 
}
 
 
/***********************************************************************
 
* Main code + dispatcher
 
**********************************************************************/
 
int UHD_SAFE_MAIN(int argc, char *argv[]){
 
    uhd::set_thread_priority_safe();
 
 
    //variables to be set by po
 
    std::string args;
 
    double duration;
 
    double rx_rate, tx_rate;
 
    std::string rx_otw, tx_otw;
 
    std::string rx_cpu, tx_cpu;
 
    std::string mode, ref, pps;
 
    std::string channel_list;
 
    bool random_nsamps = false;
 
    atomic_bool burst_timer_elapsed(false);
 
 
    //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")
 
        ("duration", po::value<double>(&duration)->default_value(10.0), "duration for the test in seconds")
 
        ("rx_rate", po::value<double>(&rx_rate), "specify to perform a RX rate test (sps)")
 
        ("tx_rate", po::value<double>(&tx_rate), "specify to perform a TX rate test (sps)")
 
        ("rx_otw", po::value<std::string>(&rx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for RX")
 
        ("tx_otw", po::value<std::string>(&tx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for TX")
 
        ("rx_cpu", po::value<std::string>(&rx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for RX")
 
        ("tx_cpu", po::value<std::string>(&tx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for TX")
 
        ("ref", po::value<std::string>(&ref), "clock reference (internal, external, mimo, gpsdo)")
 
        ("pps", po::value<std::string>(&pps), "PPS source (internal, external, mimo, gpsdo)")
 
        ("mode", po::value<std::string>(&mode), "DEPRECATED - use \"ref\" and \"pps\" instead (none, mimo)")
 
        ("random", "Run with random values of samples in send() and recv() to stress-test the I/O.")
 
        ("channels", po::value<std::string>(&channel_list)->default_value("0"), "which channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)")
 
    ;
 
    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") or (vm.count("rx_rate") + vm.count("tx_rate")) == 0){
 
        std::cout << boost::format("UHD Benchmark Rate %s") % desc << std::endl;
 
        std::cout <<
 
        "    Specify --rx_rate for a receive-only test.\n"
 
        "    Specify --tx_rate for a transmit-only test.\n"
 
        "    Specify both options for a full-duplex test.\n"
 
        << std::endl;
 
        return ~0;
 
    }
 
 
    // Random number of samples?
 
    if (vm.count("random")) {
 
        std::cout << "Using random number of samples in send() and recv() calls." << std::endl;
 
        random_nsamps = true;
 
    }
 
 
    if (vm.count("mode")) {
 
        if (vm.count("pps") or vm.count("ref")) {
 
            std::cout << "ERROR: The \"mode\" parameter cannot be used with the \"ref\" and \"pps\" parameters.\n" << std::endl;
 
            return -1;
 
        } else if (mode == "mimo") {
 
            ref = pps = "mimo";
 
            std::cout << "The use of the \"mode\" parameter is deprecated.  Please use \"ref\" and \"pps\" parameters instead\n" << std::endl;
 
        }
 
    }
 
 
    //create a usrp device
 
    std::cout << std::endl;
 
    uhd::device_addrs_t device_addrs = uhd::device::find(args, uhd::device::USRP);
 
    if (not device_addrs.empty() and device_addrs.at(0).get("type", "") == "usrp1"){
 
        std::cerr << "*** Warning! ***" << std::endl;
 
        std::cerr << "Benchmark results will be inaccurate on USRP1 due to insufficient features.\n" << std::endl;
 
    }
 
    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;
 
    int num_mboards = usrp->get_num_mboards();
 
 
    boost::thread_group thread_group;
 
 
    if(vm.count("ref"))
 
    {
 
        if (ref == "mimo")
 
        {
 
            if (num_mboards != 2) {
 
                std::cerr << "ERROR: ref = \"mimo\" implies 2 motherboards; your system has " << num_mboards << " boards" << std::endl;
 
                return -1;
 
            }
 
            usrp->set_clock_source("mimo",1);
 
        } else {
 
            usrp->set_clock_source(ref);
 
        }
 
 
        if(ref != "internal") {
 
            std::cout << "Now confirming lock on clock signals..." << std::endl;
 
            bool is_locked = false;
 
            boost::system_time end_time = boost::get_system_time() + boost::posix_time::milliseconds(80);
 
            for (int i = 0; i < num_mboards; i++) {
 
                if (ref == "mimo" and i == 0) continue;
 
                while((is_locked = usrp->get_mboard_sensor("ref_locked",i).to_bool()) == false and
 
                            boost::get_system_time() < end_time )
 
                {
 
                    boost::this_thread::sleep(boost::posix_time::milliseconds(1));
 
                }
 
                if (is_locked == false) {
 
                    std::cerr << "ERROR: Unable to confirm clock signal locked on board:" << i <<  std::endl;
 
                    return -1;
 
                }
 
                is_locked = false;
 
            }
 
        }
 
    }
 
 
    if(vm.count("pps"))
 
    {
 
      if(pps == "mimo")
 
      {
 
          if (num_mboards != 2) {
 
              std::cerr << "ERROR: ref = \"mimo\" implies 2 motherboards; your system has " << num_mboards << " boards" << std::endl;
 
              return -1;
 
          }
 
          //make mboard 1 a slave over the MIMO Cable
 
          usrp->set_time_source("mimo", 1);
 
      } else {
 
          usrp->set_time_source(pps);
 
      }
 
    }
 
 
    //detect which channels to use
 
    std::vector<std::string> channel_strings;
 
    std::vector<size_t> channel_nums;
 
    boost::split(channel_strings, channel_list, boost::is_any_of("\"',"));
 
    for(size_t ch = 0; ch < channel_strings.size(); ch++){
 
        size_t chan = boost::lexical_cast<int>(channel_strings[ch]);
 
        if(chan >= usrp->get_tx_num_channels() or chan >= usrp->get_rx_num_channels()){
 
            throw std::runtime_error("Invalid channel(s) specified.");
 
        }
 
        else channel_nums.push_back(boost::lexical_cast<int>(channel_strings[ch]));
 
    }
 
 
    std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
 
    if (pps == "mimo" or ref == "mimo" or channel_nums.size() == 1) {
 
      usrp->set_time_now(0.0);
 
    } else {
 
      usrp->set_time_unknown_pps(uhd::time_spec_t(0.0));
 
    }
 
 
    //spawn the receive test thread
 
    if (vm.count("rx_rate")){
 
        usrp->set_rx_rate(rx_rate);
 
        //create a receive streamer
 
        uhd::stream_args_t stream_args(rx_cpu, rx_otw);
 
        stream_args.channels = channel_nums;
 
        uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
 
        thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_cpu, rx_stream, random_nsamps, boost::ref(burst_timer_elapsed)));
 
    }
 
 
    //spawn the transmit test thread
 
    if (vm.count("tx_rate")){
 
        usrp->set_tx_rate(tx_rate);
 
        //create a transmit streamer
 
        uhd::stream_args_t stream_args(tx_cpu, tx_otw);
 
        stream_args.channels = channel_nums;
 
        uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
 
        thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_cpu, tx_stream, boost::ref(burst_timer_elapsed), random_nsamps));
 
        thread_group.create_thread(boost::bind(&benchmark_tx_rate_async_helper, tx_stream, boost::ref(burst_timer_elapsed)));
 
    }
 
 
    //sleep for the required duration
 
    const long secs = long(duration);
 
    const long usecs = long((duration - secs)*1e6);
 
    boost::this_thread::sleep(boost::posix_time::seconds(secs) + boost::posix_time::microseconds(usecs));
 
 
    //interrupt and join the threads
 
    //burst_timer_elapsed.store(true, boost::memory_order_relaxed);
 
    burst_timer_elapsed = true;
 
    thread_group.join_all();
 
 
    //print summary
 
    std::cout << std::endl << boost::format(
 
        "Benchmark rate summary:\n"
 
        "  Num received samples:    %u\n"
 
        "  Num dropped samples:    %u\n"
 
        "  Num overflows detected:  %u\n"
 
        "  Num transmitted samples: %u\n"
 
        "  Num sequence errors:    %u\n"
 
        "  Num underflows detected: %u\n"
 
        "  Num timeouts:            %u\n"
 
    ) % num_rx_samps % num_dropped_samps
 
      % num_overflows % num_tx_samps
 
      % num_seq_errors % num_underflows
 
      % num_timeouts << std::endl;
 
 
    //finished
 
    std::cout << std::endl << "Done!" << std::endl << std::endl;
 
    return EXIT_SUCCESS;
 
}
 
 
</syntaxhighlight>
 
  
 
[[Category:Application Notes]]
 
[[Category:Application Notes]]

Revision as of 00:11, 4 May 2016

Application Note Number

AN-204

Revision History

Date Author Details
2016-05-01 Neel Pandeya
Nate Temple
Initial creation

Abstract

This AN explains how to write and build C++ programs that use the UHD API.

Overview

This Application Note will walk through building a basic C++ program with UHD. This program will initialize, configure the USRP device, set the sample rate, frequency, gain, bandwidth, and select the antenna.

Example code:

#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/exception.hpp>
#include <uhd/types/tune_request.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread.hpp>
#include <iostream>

int UHD_SAFE_MAIN(int argc, char *argv[]) {
    uhd::set_thread_priority_safe();

    std::string device_args("addr=192.168.10.2");
    std::string subdev("A:0");
    std::string ant("TX/RX");
    std::string ref("internal");

    double rate(1e6);
    double freq(915e6);
    double gain(10);
    double bw(1e6);

    //create a usrp device
    std::cout << std::endl;
    std::cout << boost::format("Creating the usrp device with: %s...") % device_args << std::endl;
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_args);

    // Lock mboard clocks
    std::cout << boost::format("Lock mboard clocks: %f") % ref << std::endl;
    usrp->set_clock_source(ref);
    
    //always select the subdevice first, the channel mapping affects the other settings
    std::cout << boost::format("subdev set to: %f") % subdev << std::endl;
    usrp->set_rx_subdev_spec(subdev);
    std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;

    //set the sample rate
    if (rate <= 0.0) {
        std::cerr << "Please specify a valid sample rate" << std::endl;
        return ~0;
    }

    // set 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;

    // set freq
    std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq / 1e6) << std::endl;
    uhd::tune_request_t tune_request(freq);
    usrp->set_rx_freq(tune_request);
    std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq() / 1e6) << std::endl << std::endl;

    // set the rf gain
    std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
    usrp->set_rx_gain(gain);
    std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;

    // set the IF filter bandwidth
    std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % (bw / 1e6) << std::endl;
    usrp->set_rx_bandwidth(bw);
    std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % (usrp->get_rx_bandwidth() / 1e6) << std::endl << std::endl;

    // set the antenna
    std::cout << boost::format("Setting RX Antenna: %s") % ant << std::endl;
    usrp->set_rx_antenna(ant);
    std::cout << boost::format("Actual RX Antenna: %s") % usrp->get_rx_antenna() << std::endl << std::endl;

    return EXIT_SUCCESS;
}


Use the uhd/host/examples/init_usrp/CMakeLists.txt file as template - Add the names of your C++ source files to the add_executable(...) section - Put both modified CMakeLists.txt file and C++ file into an empty folder - Create a “build” folder and invoke CMake the usual way:

   mkdir build
   cd build
   cmake ../
   make -j4