uhd/host/examples/tx_samples_from_file.cpp
Ciro Nishiguchi 60a70f7142 examples: remove thread priority elevation
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.
2019-10-22 16:18:46 -07:00

237 lines
9 KiB
C++

//
// Copyright 2011-2012,2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <uhd/types/tune_request.hpp>
#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 <chrono>
#include <complex>
#include <csignal>
#include <fstream>
#include <iostream>
#include <thread>
namespace po = boost::program_options;
static bool stop_signal_called = false;
void sig_int_handler(int)
{
stop_signal_called = true;
}
template <typename samp_type>
void send_from_file(
uhd::tx_streamer::sptr tx_stream, const std::string& file, size_t samps_per_buff)
{
uhd::tx_metadata_t md;
md.start_of_burst = false;
md.end_of_burst = false;
std::vector<samp_type> buff(samps_per_buff);
std::ifstream infile(file.c_str(), std::ifstream::binary);
// loop until the entire file has been read
while (not md.end_of_burst and not stop_signal_called) {
infile.read((char*)&buff.front(), buff.size() * sizeof(samp_type));
size_t num_tx_samps = size_t(infile.gcount() / sizeof(samp_type));
md.end_of_burst = infile.eof();
tx_stream->send(&buff.front(), num_tx_samps, md);
}
infile.close();
}
int UHD_SAFE_MAIN(int argc, char* argv[])
{
// variables to be set by po
std::string args, file, type, ant, subdev, ref, wirefmt, channel;
size_t spb;
double rate, freq, gain, bw, delay, lo_offset;
// 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(""), "multi uhd device address args")
("file", po::value<std::string>(&file)->default_value("usrp_samples.dat"), "name of the file to read binary samples from")
("type", po::value<std::string>(&type)->default_value("short"), "sample type: double, float, or short")
("spb", po::value<size_t>(&spb)->default_value(10000), "samples per buffer")
("rate", po::value<double>(&rate), "rate of outgoing samples")
("freq", po::value<double>(&freq), "RF center frequency in Hz")
("lo-offset", po::value<double>(&lo_offset)->default_value(0.0),
"Offset for frontend LO in Hz (optional)")
("lo_off", po::value<double>(&lo_offset),
"(DEPRECATED) will go away soon! Use --lo-offset instead")
("gain", po::value<double>(&gain), "gain for the RF chain")
("ant", po::value<std::string>(&ant), "antenna selection")
("subdev", po::value<std::string>(&subdev), "subdevice specification")
("bw", po::value<double>(&bw), "analog frontend filter bandwidth in Hz")
("ref", po::value<std::string>(&ref)->default_value("internal"), "reference source (internal, external, mimo)")
("wirefmt", po::value<std::string>(&wirefmt)->default_value("sc16"), "wire format (sc8 or sc16)")
("delay", po::value<double>(&delay)->default_value(0.0), "specify a delay between repeated transmission of file (in seconds)")
("channel", po::value<std::string>(&channel)->default_value("0"), "which channel to use")
("repeat", "repeatedly transmit file")
("int-n", "tune USRP with integer-n tuning")
;
// 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 samples from file %s") % desc << std::endl;
return ~0;
}
bool repeat = vm.count("repeat") > 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);
// Lock mboard clocks
usrp->set_clock_source(ref);
// always select the subdevice first, the channel mapping affects the other settings
if (vm.count("subdev"))
usrp->set_tx_subdev_spec(subdev);
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
// set the sample rate
if (not vm.count("rate")) {
std::cerr << "Please specify the sample rate with --rate" << std::endl;
return ~0;
}
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;
// set the center frequency
if (not vm.count("freq")) {
std::cerr << "Please specify the center frequency with --freq" << std::endl;
return ~0;
}
std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq / 1e6) << std::endl;
std::cout << boost::format("Setting TX LO Offset: %f MHz...") % (lo_offset / 1e6)
<< std::endl;
uhd::tune_request_t tune_request;
tune_request = uhd::tune_request_t(freq, lo_offset);
if (vm.count("int-n"))
tune_request.args = uhd::device_addr_t("mode_n=integer");
usrp->set_tx_freq(tune_request);
std::cout << boost::format("Actual TX Freq: %f MHz...") % (usrp->get_tx_freq() / 1e6)
<< std::endl
<< std::endl;
// set the rf gain
if (vm.count("gain")) {
std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl;
usrp->set_tx_gain(gain);
std::cout << boost::format("Actual TX Gain: %f dB...") % usrp->get_tx_gain()
<< std::endl
<< std::endl;
}
// set the analog frontend filter bandwidth
if (vm.count("bw")) {
std::cout << boost::format("Setting TX Bandwidth: %f MHz...") % (bw / 1e6)
<< std::endl;
usrp->set_tx_bandwidth(bw);
std::cout << boost::format("Actual TX Bandwidth: %f MHz...")
% (usrp->get_tx_bandwidth() / 1e6)
<< std::endl
<< std::endl;
}
// set the antenna
if (vm.count("ant"))
usrp->set_tx_antenna(ant);
// allow for some setup time:
std::this_thread::sleep_for(std::chrono::seconds(1));
// Check Ref and LO Lock detect
std::vector<std::string> sensor_names;
sensor_names = usrp->get_tx_sensor_names(0);
if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked")
!= sensor_names.end()) {
uhd::sensor_value_t lo_locked = usrp->get_tx_sensor("lo_locked", 0);
std::cout << boost::format("Checking TX: %s ...") % lo_locked.to_pp_string()
<< std::endl;
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
if ((ref == "mimo")
and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked")
!= sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked", 0);
std::cout << boost::format("Checking TX: %s ...") % mimo_locked.to_pp_string()
<< std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
if ((ref == "external")
and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked")
!= sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked", 0);
std::cout << boost::format("Checking TX: %s ...") % ref_locked.to_pp_string()
<< std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
}
// set sigint if user wants to receive
if (repeat) {
std::signal(SIGINT, &sig_int_handler);
std::cout << "Press Ctrl + C to stop streaming..." << std::endl;
}
// create a transmit streamer
std::string cpu_format;
std::vector<size_t> channel_nums;
if (type == "double")
cpu_format = "fc64";
else if (type == "float")
cpu_format = "fc32";
else if (type == "short")
cpu_format = "sc16";
uhd::stream_args_t stream_args(cpu_format, wirefmt);
channel_nums.push_back(boost::lexical_cast<size_t>(channel));
stream_args.channels = channel_nums;
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
// send from file
do {
if (type == "double")
send_from_file<std::complex<double>>(tx_stream, file, spb);
else if (type == "float")
send_from_file<std::complex<float>>(tx_stream, file, spb);
else if (type == "short")
send_from_file<std::complex<short>>(tx_stream, file, spb);
else
throw std::runtime_error("Unknown type " + type);
if (repeat and delay > 0.0) {
std::this_thread::sleep_for(std::chrono::milliseconds(int64_t(delay * 1000)));
}
} while (repeat and not stop_signal_called);
// finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
return EXIT_SUCCESS;
}