diff options
Diffstat (limited to 'host/examples')
-rw-r--r-- | host/examples/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/examples/benchmark_rate.cpp | 65 | ||||
-rw-r--r-- | host/examples/rx_samples_to_file.cpp | 200 | ||||
-rw-r--r-- | host/examples/rx_timed_samples.cpp | 1 | ||||
-rw-r--r-- | host/examples/test_pps_input.cpp | 5 | ||||
-rw-r--r-- | host/examples/transport_hammer.cpp | 280 | ||||
-rw-r--r-- | host/examples/tx_bursts.cpp | 1 | ||||
-rw-r--r-- | host/examples/tx_waveforms.cpp | 49 | ||||
-rw-r--r-- | host/examples/txrx_loopback_to_file.cpp | 47 | ||||
-rw-r--r-- | host/examples/wavetable.hpp | 66 |
10 files changed, 226 insertions, 489 deletions
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 1e6f2f013..598e42302 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -29,7 +29,6 @@ SET(example_sources test_messages.cpp test_pps_input.cpp test_timed_commands.cpp - transport_hammer.cpp tx_bursts.cpp tx_samples_from_file.cpp tx_timed_samples.cpp diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp index 03d8f3477..7ff8b9939 100644 --- a/host/examples/benchmark_rate.cpp +++ b/host/examples/benchmark_rate.cpp @@ -43,7 +43,12 @@ unsigned long long num_seq_errors = 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){ +void benchmark_rx_rate( + uhd::usrp::multi_usrp::sptr usrp, + const std::string &rx_cpu, + uhd::rx_streamer::sptr rx_stream, + bool random_nsamps +) { uhd::set_thread_priority_safe(); //print pre-test summary @@ -68,15 +73,19 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_c rx_stream->issue_stream_cmd(cmd); while (not boost::this_thread::interruption_requested()){ + 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)*rx_stream->get_num_channels(); + num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md)*rx_stream->get_num_channels(); } catch (...) { - /* apparently, the boost thread interruption can sometimes result in - throwing exceptions not of type boost::exception, this catch allows - this thread to still attempt to issue the STREAM_MODE_STOP_CONTINUOUS - */ - break; + /* apparently, the boost thread interruption can sometimes result in + throwing exceptions not of type boost::exception, this catch allows + this thread to still attempt to issue the STREAM_MODE_STOP_CONTINUOUS + */ + break; } //handle the error codes @@ -109,7 +118,12 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_c /*********************************************************************** * Benchmark TX Rate **********************************************************************/ -void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_cpu, uhd::tx_streamer::sptr tx_stream){ +void benchmark_tx_rate( + uhd::usrp::multi_usrp::sptr usrp, + const std::string &tx_cpu, + uhd::tx_streamer::sptr tx_stream, + bool random_nsamps=false +) { uhd::set_thread_priority_safe(); //print pre-test summary @@ -127,9 +141,25 @@ void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_c buffs.push_back(&buff.front()); //same buffer for each channel md.has_time_spec = (buffs.size() != 1); - while (not boost::this_thread::interruption_requested()){ - num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md)*tx_stream->get_num_channels();; - md.has_time_spec = false; + if (random_nsamps) { + std::srand( time(NULL) ); + while(not boost::this_thread::interruption_requested()){ + 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)); + while(num_acc_samps < total_num_samps){ + //send a single packet + num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md, timeout)*tx_stream->get_num_channels(); + num_acc_samps += std::min(total_num_samps-num_acc_samps, tx_stream->get_max_num_samps()); + } + } + } else { + while (not boost::this_thread::interruption_requested()){ + 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 @@ -182,6 +212,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string rx_cpu, tx_cpu; std::string mode; std::string channel_list; + bool random_nsamps = false; //setup the program options po::options_description desc("Allowed options"); @@ -196,6 +227,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("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") ("mode", po::value<std::string>(&mode)->default_value("none"), "multi-channel sync mode option: 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; @@ -213,6 +245,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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; + } + //create a usrp device std::cout << std::endl; uhd::device_addrs_t device_addrs = uhd::device::find(args, uhd::device::USRP); @@ -251,7 +289,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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)); + thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_cpu, rx_stream, random_nsamps)); } //spawn the transmit test thread @@ -261,7 +299,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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)); + thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_cpu, tx_stream, random_nsamps)); thread_group.create_thread(boost::bind(&benchmark_tx_rate_async_helper, tx_stream)); } @@ -287,6 +325,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //finished std::cout << std::endl << "Done!" << std::endl << std::endl; - return EXIT_SUCCESS; } diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp index 4fe438798..4e6d8139f 100644 --- a/host/examples/rx_samples_to_file.cpp +++ b/host/examples/rx_samples_to_file.cpp @@ -56,7 +56,7 @@ template<typename samp_type> void recv_to_file( std::vector<samp_type> buff(samps_per_buff); std::ofstream outfile; if (not null) - outfile.open(file.c_str(), std::ofstream::binary); + outfile.open(file.c_str(), std::ofstream::binary); bool overflow_message = true; //setup streaming @@ -78,8 +78,8 @@ template<typename samp_type> void recv_to_file( typedef std::map<size_t,size_t> SizeMap; SizeMap mapSizes; - while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)){ - boost::system_time now = boost::get_system_time(); + while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)) { + boost::system_time now = boost::get_system_time(); size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, 3.0, enable_size_map); @@ -88,7 +88,7 @@ template<typename samp_type> void recv_to_file( break; } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW){ - if (overflow_message){ + if (overflow_message) { overflow_message = false; std::cerr << boost::format( "Got an overflow indication. Please consider the following:\n" @@ -110,99 +110,99 @@ template<typename samp_type> void recv_to_file( throw std::runtime_error(error); } - if (enable_size_map){ - SizeMap::iterator it = mapSizes.find(num_rx_samps); - if (it == mapSizes.end()) - mapSizes[num_rx_samps] = 0; - mapSizes[num_rx_samps] += 1; - } + if (enable_size_map) { + SizeMap::iterator it = mapSizes.find(num_rx_samps); + if (it == mapSizes.end()) + mapSizes[num_rx_samps] = 0; + mapSizes[num_rx_samps] += 1; + } num_total_samps += num_rx_samps; - if (outfile.is_open()) - outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type)); - - if (bw_summary){ - last_update_samps += num_rx_samps; - boost::posix_time::time_duration update_diff = now - last_update; - if (update_diff.ticks() > boost::posix_time::time_duration::ticks_per_second()) { - double t = (double)update_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); - double r = (double)last_update_samps / t; - std::cout << boost::format("\t%f Msps") % (r/1e6) << std::endl; - last_update_samps = 0; - last_update = now; - } - } + if (outfile.is_open()) + outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type)); + + if (bw_summary) { + last_update_samps += num_rx_samps; + boost::posix_time::time_duration update_diff = now - last_update; + if (update_diff.ticks() > boost::posix_time::time_duration::ticks_per_second()) { + double t = (double)update_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); + double r = (double)last_update_samps / t; + std::cout << boost::format("\t%f Msps") % (r/1e6) << std::endl; + last_update_samps = 0; + last_update = now; + } + } ticks_diff = now - start; - if (ticks_requested > 0){ - if ((unsigned long long)ticks_diff.ticks() > ticks_requested) - break; - } + if (ticks_requested > 0){ + if ((unsigned long long)ticks_diff.ticks() > ticks_requested) + break; + } } stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; rx_stream->issue_stream_cmd(stream_cmd); if (outfile.is_open()) - outfile.close(); - - if (stats){ - std::cout << std::endl; - - double t = (double)ticks_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); - std::cout << boost::format("Received %d samples in %f seconds") % num_total_samps % t << std::endl; - double r = (double)num_total_samps / t; - std::cout << boost::format("%f Msps") % (r/1e6) << std::endl; - - if (enable_size_map) { - std::cout << std::endl; - std::cout << "Packet size map (bytes: count)" << std::endl; - for (SizeMap::iterator it = mapSizes.begin(); it != mapSizes.end(); it++) - std::cout << it->first << ":\t" << it->second << std::endl; - } - } + outfile.close(); + + if (stats) { + std::cout << std::endl; + + double t = (double)ticks_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); + std::cout << boost::format("Received %d samples in %f seconds") % num_total_samps % t << std::endl; + double r = (double)num_total_samps / t; + std::cout << boost::format("%f Msps") % (r/1e6) << std::endl; + + if (enable_size_map) { + std::cout << std::endl; + std::cout << "Packet size map (bytes: count)" << std::endl; + for (SizeMap::iterator it = mapSizes.begin(); it != mapSizes.end(); it++) + std::cout << it->first << ":\t" << it->second << std::endl; + } + } } typedef boost::function<uhd::sensor_value_t (const std::string&)> get_sensor_fn_t; bool check_locked_sensor(std::vector<std::string> sensor_names, const char* sensor_name, get_sensor_fn_t get_sensor_fn, double setup_time){ - if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end()) - return false; - - boost::system_time start = boost::get_system_time(); - boost::system_time first_lock_time; - - std::cout << boost::format("Waiting for \"%s\": ") % sensor_name; - std::cout.flush(); - - while (true){ - if ((not first_lock_time.is_not_a_date_time()) and - (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(setup_time)))) - { - std::cout << " locked." << std::endl; - break; - } - if (get_sensor_fn(sensor_name).to_bool()){ - if (first_lock_time.is_not_a_date_time()) - first_lock_time = boost::get_system_time(); - std::cout << "+"; - std::cout.flush(); - } - else{ - first_lock_time = boost::system_time(); //reset to 'not a date time' - - if (boost::get_system_time() > (start + boost::posix_time::seconds(setup_time))){ - std::cout << std::endl; - throw std::runtime_error(str(boost::format("timed out waiting for consecutive locks on sensor \"%s\"") % sensor_name)); - } - std::cout << "_"; - std::cout.flush(); - } - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } - std::cout << std::endl; - return true; + if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end()) + return false; + + boost::system_time start = boost::get_system_time(); + boost::system_time first_lock_time; + + std::cout << boost::format("Waiting for \"%s\": ") % sensor_name; + std::cout.flush(); + + while (true) { + if ((not first_lock_time.is_not_a_date_time()) and + (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(setup_time)))) + { + std::cout << " locked." << std::endl; + break; + } + if (get_sensor_fn(sensor_name).to_bool()){ + if (first_lock_time.is_not_a_date_time()) + first_lock_time = boost::get_system_time(); + std::cout << "+"; + std::cout.flush(); + } + else { + first_lock_time = boost::system_time(); //reset to 'not a date time' + + if (boost::get_system_time() > (start + boost::posix_time::seconds(setup_time))){ + std::cout << std::endl; + throw std::runtime_error(str(boost::format("timed out waiting for consecutive locks on sensor \"%s\"") % sensor_name)); + } + std::cout << "_"; + std::cout.flush(); + } + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + std::cout << std::endl; + return true; } int UHD_SAFE_MAIN(int argc, char *argv[]){ @@ -246,8 +246,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::notify(vm); //print the help message - if (vm.count("help")){ + if (vm.count("help")) { std::cout << boost::format("UHD RX samples to file %s") % desc << std::endl; + std::cout + << std::endl + << "This application streams data from a single channel of a USRP device to a file.\n" + << std::endl; return ~0; } @@ -258,7 +262,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ bool continue_on_bad_packet = vm.count("continue") > 0; if (enable_size_map) - std::cout << "Packet size tracking enabled - will only recv one packet at a time!" << std::endl; + std::cout << "Packet size tracking enabled - will only recv one packet at a time!" << std::endl; //create a usrp device std::cout << std::endl; @@ -283,23 +287,23 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl; //set the center frequency - if (vm.count("freq")){ //with default of 0.0 this will always be true - std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl; + if (vm.count("freq")) { //with default of 0.0 this will always be true + std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl; uhd::tune_request_t tune_request(freq); if(vm.count("int-n")) tune_request.args = uhd::device_addr_t("mode_n=integer"); - usrp->set_rx_freq(tune_request); - std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << 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; + } //set the rf gain - if (vm.count("gain")){ + if (vm.count("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 analog frontend filter bandwidth - if (vm.count("bw")){ + //set the IF filter bandwidth + if (vm.count("bw")) { std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl; usrp->set_rx_bandwidth(bw); std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl; @@ -312,12 +316,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //check Ref and LO Lock detect if (not vm.count("skip-lo")){ - check_locked_sensor(usrp->get_rx_sensor_names(0), "lo_locked", boost::bind(&uhd::usrp::multi_usrp::get_rx_sensor, usrp, _1, 0), setup_time); - if (ref == "mimo") - check_locked_sensor(usrp->get_mboard_sensor_names(0), "mimo_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time); - if (ref == "external") - check_locked_sensor(usrp->get_mboard_sensor_names(0), "ref_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time); - } + check_locked_sensor(usrp->get_rx_sensor_names(0), "lo_locked", boost::bind(&uhd::usrp::multi_usrp::get_rx_sensor, usrp, _1, 0), setup_time); + if (ref == "mimo") + check_locked_sensor(usrp->get_mboard_sensor_names(0), "mimo_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time); + if (ref == "external") + check_locked_sensor(usrp->get_mboard_sensor_names(0), "ref_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time); + } if (total_num_samps == 0){ std::signal(SIGINT, &sig_int_handler); @@ -325,7 +329,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } #define recv_to_file_args(format) \ - (usrp, format, wirefmt, file, spb, total_num_samps, total_time, bw_summary, stats, null, enable_size_map, continue_on_bad_packet) + (usrp, format, wirefmt, file, spb, total_num_samps, total_time, bw_summary, stats, null, enable_size_map, continue_on_bad_packet) //recv to file if (type == "double") recv_to_file<std::complex<double> >recv_to_file_args("fc64"); else if (type == "float") recv_to_file<std::complex<float> >recv_to_file_args("fc32"); diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 30535907f..20abd92fe 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -48,7 +48,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples") ("dilv", "specify to disable inner-loop verbose") ("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); diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp index 889c98a45..3e6c4ba9d 100644 --- a/host/examples/test_pps_input.cpp +++ b/host/examples/test_pps_input.cpp @@ -47,6 +47,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //print the help message if (vm.count("help")){ std::cout << boost::format("UHD Test PPS Input %s") % desc << std::endl; + std::cout + << std::endl + << "Tests if the PPS input signal is working. Will throw an error if not." + << std::endl + << std::endl; return ~0; } diff --git a/host/examples/transport_hammer.cpp b/host/examples/transport_hammer.cpp deleted file mode 100644 index 32e344e3e..000000000 --- a/host/examples/transport_hammer.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// -// 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/convert.hpp> -#include <uhd/utils/safe_main.hpp> -#include <uhd/usrp/multi_usrp.hpp> -#include <boost/program_options.hpp> -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> -#include <boost/math/special_functions/round.hpp> -#include <iostream> -#include <complex> - -namespace po = boost::program_options; - -/*********************************************************************** - * 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; - -/*********************************************************************** - * RX Hammer - **********************************************************************/ -void rx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, uhd::rx_streamer::sptr rx_stream){ - uhd::set_thread_priority_safe(); - - //print pre-test summary - std::cout << boost::format( - "Testing receive rate %f Msps" - ) % (usrp->get_rx_rate()/1e6) << std::endl; - - //setup variables and allocate buffer - uhd::rx_metadata_t md; - const size_t max_samps_per_packet = rx_stream->get_max_num_samps(); - std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(rx_cpu)); - 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(); - double timeout = 1; - - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); - cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(0.05); - cmd.stream_now = (buffs.size() == 1); - srand( time(NULL) ); - - while (not boost::this_thread::interruption_requested()){ - cmd.num_samps = rand() % 100000; - rx_stream->issue_stream_cmd(cmd); - num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md, timeout, true); - - //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 += boost::math::iround((md.time_spec - last_time).get_real_secs()*rate); - } - break; - - case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: - had_an_overflow = true; - last_time = md.time_spec; - if (!md.out_of_sequence) - num_overflows++; - break; - - default: - std::cerr << "Receiver error: " << md.strerror() << std::endl; - std::cerr << "Unexpected error on recv, continuing..." << std::endl; - break; - } - } -} - -/*********************************************************************** - * TX Hammer - **********************************************************************/ -void tx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_cpu, uhd::tx_streamer::sptr tx_stream){ - uhd::set_thread_priority_safe(); - - uhd::tx_metadata_t md; - 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<void *> buffs; - for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++) - buffs.push_back(&buff.front()); //same buffer for each channel - - //print pre-test summary - std::cout << boost::format( - "Testing transmit rate %f Msps" - ) % (usrp->get_tx_rate()/1e6) << std::endl; - - //setup variables and allocate buffer - std::srand( time(NULL) ); - while(not boost::this_thread::interruption_requested()){ - size_t total_num_samps = rand() % 100000; - size_t num_acc_samps = 0; - float timeout = 1; - - usrp->set_time_now(uhd::time_spec_t(0.0)); - while(num_acc_samps < total_num_samps){ - - //send a single packet - num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md, timeout); - - num_acc_samps += std::min(total_num_samps-num_acc_samps, tx_stream->get_max_num_samps()); - } - //send a mini EOB packet - md.end_of_burst = true; - tx_stream->send("", 0, md); - } -} - -void tx_hammer_async_helper(uhd::tx_streamer::sptr tx_stream){ - //setup variables and allocate buffer - uhd::async_metadata_t async_md; - - while (not boost::this_thread::interruption_requested()){ - - if (not tx_stream->recv_async_msg(async_md)) continue; - - //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; - - //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), "if random, specify 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") - ("mode", po::value<std::string>(&mode)->default_value("none"), "multi-channel sync mode option: none, mimo") - ; - 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 Transport Hammer - %s") % desc << std::endl; - std::cout << - "UHD Transport Hammer: a transport layer stress test that continuously\n" - "calls for random amounts of TX and RX samples\n\n"; - std::cout << desc << std::endl << - " 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; - } - - //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 << "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; - - if (mode == "mimo"){ - usrp->set_clock_source("mimo", 0); - usrp->set_time_source("mimo", 0); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - } - - boost::thread_group thread_group; - - //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); - for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping - stream_args.channels.push_back(ch); - uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); - thread_group.create_thread(boost::bind(&rx_hammer, usrp, rx_cpu, rx_stream)); - } - - //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); - for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping - stream_args.channels.push_back(ch); - uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); - thread_group.create_thread(boost::bind(&tx_hammer, usrp, tx_cpu, tx_stream)); - thread_group.create_thread(boost::bind(&tx_hammer_async_helper, tx_stream)); - } - - //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 - thread_group.interrupt_all(); - thread_group.join_all(); - - //print summary - std::cout << std::endl << boost::format( - "Transport Hammer 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_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_seq_errors % num_underflows << std::endl; - - //finished - std::cout << std::endl << "Done!" << std::endl << std::endl; - - return EXIT_SUCCESS; -} diff --git a/host/examples/tx_bursts.cpp b/host/examples/tx_bursts.cpp index fec89a0e4..bb71d4581 100644 --- a/host/examples/tx_bursts.cpp +++ b/host/examples/tx_bursts.cpp @@ -148,7 +148,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ size_t num_tx_samps = tx_stream->send( buffs, samps_to_send, md, timeout ); - //do not use time spec for subsequent packets md.has_time_spec = false; md.start_of_burst = false; diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 7e633262c..9254c3b24 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "wavetable.hpp" #include <uhd/utils/thread_priority.hpp> #include <uhd/utils/safe_main.hpp> #include <uhd/utils/static.hpp> @@ -28,9 +29,7 @@ #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> #include <iostream> -#include <complex> #include <csignal> -#include <cmath> namespace po = boost::program_options; @@ -41,52 +40,6 @@ static bool stop_signal_called = false; void sig_int_handler(int){stop_signal_called = true;} /*********************************************************************** - * Waveform generators - **********************************************************************/ -static const size_t wave_table_len = 8192; - -class wave_table_class{ -public: - wave_table_class(const std::string &wave_type, const float ampl): - _wave_table(wave_table_len) - { - //compute real wave table with 1.0 amplitude - std::vector<double> real_wave_table(wave_table_len); - if (wave_type == "CONST"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = 1.0; - } - else if (wave_type == "SQUARE"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0; - } - else if (wave_type == "RAMP"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0; - } - else if (wave_type == "SINE"){ - static const double tau = 2*std::acos(-1.0); - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = std::sin((tau*i)/wave_table_len); - } - else throw std::runtime_error("unknown waveform type: " + wave_type); - - //compute i and q pairs with 90% offset and scale to amplitude - for (size_t i = 0; i < wave_table_len; i++){ - const size_t q = (i+(3*wave_table_len)/4)%wave_table_len; - _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]); - } - } - - inline std::complex<float> operator()(const size_t index) const{ - return _wave_table[index % wave_table_len]; - } - -private: - std::vector<std::complex<float> > _wave_table; -}; - -/*********************************************************************** * Main function **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ diff --git a/host/examples/txrx_loopback_to_file.cpp b/host/examples/txrx_loopback_to_file.cpp index 66c13308a..26ad2e822 100644 --- a/host/examples/txrx_loopback_to_file.cpp +++ b/host/examples/txrx_loopback_to_file.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "wavetable.hpp" #include <uhd/types/tune_request.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/utils/safe_main.hpp> @@ -31,7 +32,6 @@ #include <iostream> #include <fstream> #include <csignal> -#include <cmath> namespace po = boost::program_options; @@ -61,51 +61,6 @@ std::string generate_out_filename(const std::string &base_fn, size_t n_names, si return base_fn_fp.string(); } -/*********************************************************************** - * Waveform generators - **********************************************************************/ -static const size_t wave_table_len = 8192; - -class wave_table_class{ -public: - wave_table_class(const std::string &wave_type, const float ampl): - _wave_table(wave_table_len) - { - //compute real wave table with 1.0 amplitude - std::vector<double> real_wave_table(wave_table_len); - if (wave_type == "CONST"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = 1.0; - } - else if (wave_type == "SQUARE"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0; - } - else if (wave_type == "RAMP"){ - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0; - } - else if (wave_type == "SINE"){ - static const double tau = 2*std::acos(-1.0); - for (size_t i = 0; i < wave_table_len; i++) - real_wave_table[i] = std::sin((tau*i)/wave_table_len); - } - else throw std::runtime_error("unknown waveform type: " + wave_type); - - //compute i and q pairs with 90% offset and scale to amplitude - for (size_t i = 0; i < wave_table_len; i++){ - const size_t q = (i+(3*wave_table_len)/4)%wave_table_len; - _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]); - } - } - - inline std::complex<float> operator()(const size_t index) const{ - return _wave_table[index % wave_table_len]; - } - -private: - std::vector<std::complex<float> > _wave_table; -}; /*********************************************************************** * transmit_worker function diff --git a/host/examples/wavetable.hpp b/host/examples/wavetable.hpp new file mode 100644 index 000000000..d7ffc8406 --- /dev/null +++ b/host/examples/wavetable.hpp @@ -0,0 +1,66 @@ +// +// Copyright 2010-2012,2014 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 <string> +#include <cmath> +#include <complex> +#include <vector> +#include <stdexcept> + +static const size_t wave_table_len = 8192; + +class wave_table_class{ +public: + wave_table_class(const std::string &wave_type, const float ampl): + _wave_table(wave_table_len) + { + //compute real wave table with 1.0 amplitude + std::vector<double> real_wave_table(wave_table_len); + if (wave_type == "CONST"){ + for (size_t i = 0; i < wave_table_len; i++) + real_wave_table[i] = 1.0; + } + else if (wave_type == "SQUARE"){ + for (size_t i = 0; i < wave_table_len; i++) + real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0; + } + else if (wave_type == "RAMP"){ + for (size_t i = 0; i < wave_table_len; i++) + real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0; + } + else if (wave_type == "SINE"){ + static const double tau = 2*std::acos(-1.0); + for (size_t i = 0; i < wave_table_len; i++) + real_wave_table[i] = std::sin((tau*i)/wave_table_len); + } + else throw std::runtime_error("unknown waveform type: " + wave_type); + + //compute i and q pairs with 90% offset and scale to amplitude + for (size_t i = 0; i < wave_table_len; i++){ + const size_t q = (i+(3*wave_table_len)/4)%wave_table_len; + _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]); + } + } + + inline std::complex<float> operator()(const size_t index) const{ + return _wave_table[index % wave_table_len]; + } + +private: + std::vector<std::complex<float> > _wave_table; +}; + |