mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-15 21:01:26 +00:00
Remove UHD call to elevate thread priority to realtime. Setting all threads to the same realtime priority can cause the threads to not share access to the network interface fairly, which adversely affects operation of the worker threads in UHD.
128 lines
4.7 KiB
C++
128 lines
4.7 KiB
C++
//
|
|
// Copyright 2010-2011,2014 Ettus Research LLC
|
|
// Copyright 2018 Ettus Research, a National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
|
|
#include <uhd/usrp/multi_usrp.hpp>
|
|
#include <uhd/utils/safe_main.hpp>
|
|
#include <uhd/utils/thread.hpp>
|
|
#include <boost/format.hpp>
|
|
#include <boost/program_options.hpp>
|
|
#include <boost/thread/thread.hpp>
|
|
#include <complex>
|
|
#include <iostream>
|
|
|
|
namespace po = boost::program_options;
|
|
|
|
int UHD_SAFE_MAIN(int argc, char* argv[])
|
|
{
|
|
// variables to be set by po
|
|
std::string args;
|
|
std::string wire;
|
|
double seconds_in_future;
|
|
size_t total_num_samps;
|
|
double rate;
|
|
float ampl;
|
|
|
|
// setup the program options
|
|
po::options_description desc("Allowed options");
|
|
// clang-format off
|
|
desc.add_options()
|
|
("help", "help message")
|
|
("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
|
|
("wire", po::value<std::string>(&wire)->default_value(""), "the over the wire type, sc16, sc8, etc")
|
|
("secs", po::value<double>(&seconds_in_future)->default_value(1.5), "number of seconds in the future to transmit")
|
|
("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000), "total number of samples to transmit")
|
|
("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of outgoing samples")
|
|
("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of each sample")
|
|
("dilv", "specify to disable inner-loop verbose")
|
|
;
|
|
// clang-format on
|
|
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 TX Timed Samples %s") % desc << std::endl;
|
|
return ~0;
|
|
}
|
|
|
|
bool verbose = vm.count("dilv") == 0;
|
|
|
|
// create a usrp device
|
|
std::cout << 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;
|
|
|
|
// 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;
|
|
|
|
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
|
|
usrp->set_time_now(uhd::time_spec_t(0.0));
|
|
|
|
// create a transmit streamer
|
|
uhd::stream_args_t stream_args("fc32", wire); // 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 = true;
|
|
md.time_spec = uhd::time_spec_t(seconds_in_future);
|
|
|
|
// the first call to send() will block this many seconds before sending:
|
|
const double timeout =
|
|
seconds_in_future + 0.1; // timeout (delay before transmit + padding)
|
|
|
|
size_t num_acc_samps = 0; // number of accumulated samples
|
|
while (num_acc_samps < total_num_samps) {
|
|
size_t samps_to_send = std::min(total_num_samps - num_acc_samps, buff.size());
|
|
|
|
// send a single packet
|
|
size_t num_tx_samps = tx_stream->send(&buff.front(), samps_to_send, md, timeout);
|
|
|
|
// do not use time spec for subsequent packets
|
|
md.has_time_spec = false;
|
|
|
|
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;
|
|
}
|
|
|
|
// 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::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 tx_stream->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" : "fail") << std::endl;
|
|
|
|
// finished
|
|
std::cout << std::endl << "Done!" << std::endl << std::endl;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|