uhd/host/examples/test_messages.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

365 lines
12 KiB
C++

//
// Copyright 2010-2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <uhd/config.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/thread.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <complex>
#include <cstdlib>
#include <ctime>
#include <iostream>
namespace po = boost::program_options;
/*!
* Test the late command message:
* Issue a stream command with a time that is in the past.
* We expect to get an inline late command message.
*/
bool test_late_command_message(uhd::usrp::multi_usrp::sptr usrp,
uhd::rx_streamer::sptr rx_stream,
uhd::tx_streamer::sptr)
{
std::cout << "Test late command message... " << std::flush;
usrp->set_time_now(uhd::time_spec_t(200.0)); // set time
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = rx_stream->get_max_num_samps();
stream_cmd.stream_now = false;
stream_cmd.time_spec = uhd::time_spec_t(100.0); // time in the past
rx_stream->issue_stream_cmd(stream_cmd);
std::vector<std::complex<float>> buff(rx_stream->get_max_num_samps());
uhd::rx_metadata_t md;
const size_t nsamps = rx_stream->recv(&buff.front(), buff.size(), md);
switch (md.error_code) {
case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND:
std::cout << boost::format("success:\n"
" Got error code late command message.\n")
<< std::endl;
return true;
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
std::cout << boost::format("failed:\n"
" Inline message recv timed out.\n")
<< std::endl;
return false;
default:
std::cout << boost::format(
"failed:\n"
" Got unexpected error code 0x%x (%s), nsamps %u.\n")
% md.error_code % md.strerror() % nsamps
<< std::endl;
return false;
}
}
/*!
* Test the broken chain message:
* Issue a stream command with num samps and more.
* We expect to get an inline broken chain message.
*/
bool test_broken_chain_message(UHD_UNUSED(uhd::usrp::multi_usrp::sptr usrp),
uhd::rx_streamer::sptr rx_stream,
uhd::tx_streamer::sptr)
{
std::cout << "Test broken chain message... " << std::flush;
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
stream_cmd.stream_now = true;
stream_cmd.num_samps = rx_stream->get_max_num_samps();
rx_stream->issue_stream_cmd(stream_cmd);
std::vector<std::complex<float>> buff(rx_stream->get_max_num_samps());
uhd::rx_metadata_t md;
rx_stream->recv( // once for the requested samples
&buff.front(),
buff.size(),
md);
rx_stream->recv( // again for the inline message
&buff.front(),
buff.size(),
md);
switch (md.error_code) {
case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN:
std::cout << boost::format("success:\n"
" Got error code broken chain message.\n")
<< std::endl;
return true;
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
std::cout << boost::format("failed:\n"
" Inline message recv timed out.\n")
<< std::endl;
return false;
default:
std::cout << boost::format("failed:\n"
" Got unexpected error code 0x%x (%s).\n")
% md.error_code % md.strerror()
<< std::endl;
return false;
}
}
/*!
* Test the burst ack message:
* Send a burst of many samples that will fragment internally.
* We expect to get an burst ack async message.
*/
bool test_burst_ack_message(
uhd::usrp::multi_usrp::sptr, uhd::rx_streamer::sptr, uhd::tx_streamer::sptr tx_stream)
{
std::cout << "Test burst ack message... " << std::flush;
uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst = true;
md.has_time_spec = false;
// 3 times max-sps guarantees a SOB, no burst, and EOB packet
std::vector<std::complex<float>> buff(tx_stream->get_max_num_samps() * 3);
tx_stream->send(&buff.front(), buff.size(), md);
uhd::async_metadata_t async_md;
if (not tx_stream->recv_async_msg(async_md)) {
std::cout << boost::format("failed:\n"
" Async message recv timed out.\n")
<< std::endl;
return false;
}
switch (async_md.event_code) {
case uhd::async_metadata_t::EVENT_CODE_BURST_ACK:
std::cout << boost::format("success:\n"
" Got event code burst ack message.\n")
<< std::endl;
return true;
default:
std::cout << boost::format("failed:\n"
" Got unexpected event code 0x%x.\n")
% async_md.event_code
<< std::endl;
return false;
}
}
/*!
* Test the underflow message:
* Send a start of burst packet with no following end of burst.
* We expect to get an underflow(within a burst) async message.
*/
bool test_underflow_message(
uhd::usrp::multi_usrp::sptr, uhd::rx_streamer::sptr, uhd::tx_streamer::sptr tx_stream)
{
std::cout << "Test underflow message... " << std::flush;
uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst = false;
md.has_time_spec = false;
std::vector<std::complex<float>> buff(tx_stream->get_max_num_samps());
tx_stream->send(&buff.front(), buff.size(), md);
uhd::async_metadata_t async_md;
if (not tx_stream->recv_async_msg(async_md, 1)) {
std::cout << boost::format("failed:\n"
" Async message recv timed out.\n")
<< std::endl;
return false;
}
switch (async_md.event_code) {
case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW:
std::cout << boost::format("success:\n"
" Got event code underflow message.\n")
<< std::endl;
return true;
default:
std::cout << boost::format("failed:\n"
" Got unexpected event code 0x%x.\n")
% async_md.event_code
<< std::endl;
return false;
}
}
/*!
* Test the time error message:
* Send a burst packet that occurs at a time in the past.
* We expect to get a time error async message.
*/
bool test_time_error_message(uhd::usrp::multi_usrp::sptr usrp,
uhd::rx_streamer::sptr,
uhd::tx_streamer::sptr tx_stream)
{
std::cout << "Test time error message... " << std::flush;
uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst = true;
md.has_time_spec = true;
md.time_spec = uhd::time_spec_t(100.0); // send at 100s
usrp->set_time_now(uhd::time_spec_t(200.0)); // time at 200s
std::vector<std::complex<float>> buff(tx_stream->get_max_num_samps());
tx_stream->send(&buff.front(), buff.size(), md);
uhd::async_metadata_t async_md;
if (not tx_stream->recv_async_msg(async_md)) {
std::cout << boost::format("failed:\n"
" Async message recv timed out.\n")
<< std::endl;
return false;
}
switch (async_md.event_code) {
case uhd::async_metadata_t::EVENT_CODE_TIME_ERROR:
std::cout << boost::format("success:\n"
" Got event code time error message.\n")
<< std::endl;
return true;
default:
std::cout << boost::format("failed:\n"
" Got unexpected event code 0x%x.\n")
% async_md.event_code
<< std::endl;
return false;
}
}
void flush_async(uhd::tx_streamer::sptr tx_stream)
{
uhd::async_metadata_t async_md;
while (tx_stream->recv_async_msg(async_md)) {
}
}
void flush_recv(uhd::rx_streamer::sptr rx_stream)
{
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = rx_stream->get_max_num_samps() * 3;
stream_cmd.stream_now = true;
rx_stream->issue_stream_cmd(stream_cmd);
std::vector<std::complex<float>> buff(stream_cmd.num_samps);
uhd::rx_metadata_t md;
do {
rx_stream->recv(&buff.front(), buff.size(), md);
} while (md.error_code != uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
}
int UHD_SAFE_MAIN(int argc, char* argv[])
{
// variables to be set by po
std::string args;
size_t ntests;
// 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")
("ntests", po::value<size_t>(&ntests)->default_value(50), "number of tests to run")
("test-chain", "Run broken chain tests")
;
// 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 Test Messages %s") % desc << std::endl;
return ~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;
// create RX and TX streamers
uhd::stream_args_t stream_args("fc32"); // complex floats
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
//------------------------------------------------------------------
// begin messages test
//------------------------------------------------------------------
static uhd::dict<std::string,
boost::function<bool(
uhd::usrp::multi_usrp::sptr, uhd::rx_streamer::sptr, uhd::tx_streamer::sptr)>>
tests = boost::assign::map_list_of("Test Burst ACK ", &test_burst_ack_message)(
"Test Underflow ", &test_underflow_message)("Test Time Error",
&test_time_error_message)("Test Late Command", &test_late_command_message);
if (vm.count("test-chain")) {
tests["Test Broken Chain"] = &test_broken_chain_message;
}
// init result counts
uhd::dict<std::string, size_t> failures, successes;
for (const std::string& key : tests.keys()) {
failures[key] = 0;
successes[key] = 0;
}
// run the tests, pick at random
std::srand((unsigned int)time(NULL));
for (size_t n = 0; n < ntests; n++) {
std::string key = tests.keys()[std::rand() % tests.size()];
bool pass = tests[key](usrp, rx_stream, tx_stream);
flush_recv(rx_stream);
flush_async(tx_stream);
// store result
if (pass)
successes[key]++;
else
failures[key]++;
}
// print the result summary
bool any_failure = false;
std::cout << std::endl << "Summary:" << std::endl << std::endl;
for (const std::string& key : tests.keys()) {
std::cout << boost::format("%s -> %3u successes, %3u failures") % key
% successes[key] % failures[key]
<< std::endl;
any_failure = any_failure or (failures[key] > 0);
}
// finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
return any_failure ? EXIT_FAILURE : EXIT_SUCCESS;
}