2.4.6. tx_samples_from_file.cpp#

2.4.6.1. Source code#

  1//
  2// Copyright 2011-2012,2014 Ettus Research LLC
  3// Copyright 2018 Ettus Research, a National Instruments Company
  4//
  5// SPDX-License-Identifier: GPL-3.0-or-later
  6//
  7
  8#include <uhd/types/tune_request.hpp>
  9#include <uhd/usrp/multi_usrp.hpp>
 10#include <uhd/utils/safe_main.hpp>
 11#include <uhd/utils/thread.hpp>
 12#include <boost/format.hpp>
 13#include <boost/program_options.hpp>
 14#include <chrono>
 15#include <complex>
 16#include <csignal>
 17#include <fstream>
 18#include <iostream>
 19#include <thread>
 20
 21namespace po = boost::program_options;
 22
 23static bool stop_signal_called = false;
 24void sig_int_handler(int)
 25{
 26    stop_signal_called = true;
 27}
 28
 29template <typename samp_type>
 30void send_from_file(
 31    uhd::tx_streamer::sptr tx_stream, const std::string& file, size_t samps_per_buff)
 32{
 33    uhd::tx_metadata_t md;
 34    md.start_of_burst = false;
 35    md.end_of_burst   = false;
 36    std::vector<samp_type> buff(samps_per_buff);
 37    std::ifstream infile(file.c_str(), std::ifstream::binary);
 38
 39    // loop until the entire file has been read
 40
 41    while (not md.end_of_burst and not stop_signal_called) {
 42        infile.read((char*)&buff.front(), buff.size() * sizeof(samp_type));
 43        size_t num_tx_samps = size_t(infile.gcount() / sizeof(samp_type));
 44
 45        md.end_of_burst = infile.eof();
 46
 47        const size_t samples_sent = tx_stream->send(&buff.front(), num_tx_samps, md);
 48        if (samples_sent != num_tx_samps) {
 49            UHD_LOG_ERROR("TX-STREAM",
 50                "The tx_stream timed out sending " << num_tx_samps << " samples ("
 51                                                   << samples_sent << " sent).");
 52            return;
 53        }
 54    }
 55
 56    infile.close();
 57}
 58
 59int UHD_SAFE_MAIN(int argc, char* argv[])
 60{
 61    // variables to be set by po
 62    std::string args, file, type, ant, subdev, ref, wirefmt, channel;
 63    size_t spb;
 64    double rate, freq, gain, bw, delay, lo_offset;
 65
 66    // setup the program options
 67    po::options_description desc("Allowed options");
 68    // clang-format off
 69    desc.add_options()
 70        ("help", "help message")
 71        ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
 72        ("file", po::value<std::string>(&file)->default_value("usrp_samples.dat"), "name of the file to read binary samples from")
 73        ("type", po::value<std::string>(&type)->default_value("short"), "sample type: double, float, or short")
 74        ("spb", po::value<size_t>(&spb)->default_value(10000), "samples per buffer")
 75        ("rate", po::value<double>(&rate), "rate of outgoing samples")
 76        ("freq", po::value<double>(&freq), "RF center frequency in Hz")
 77        ("lo-offset", po::value<double>(&lo_offset)->default_value(0.0),
 78            "Offset for frontend LO in Hz (optional)")
 79        ("gain", po::value<double>(&gain), "gain for the RF chain")
 80        ("ant", po::value<std::string>(&ant), "antenna selection")
 81        ("subdev", po::value<std::string>(&subdev), "subdevice specification")
 82        ("bw", po::value<double>(&bw), "analog frontend filter bandwidth in Hz")
 83        ("ref", po::value<std::string>(&ref)->default_value("internal"), "reference source (internal, external, mimo)")
 84        ("wirefmt", po::value<std::string>(&wirefmt)->default_value("sc16"), "wire format (sc8 or sc16)")
 85        ("delay", po::value<double>(&delay)->default_value(0.0), "specify a delay between repeated transmission of file (in seconds)")
 86        ("channel", po::value<std::string>(&channel)->default_value("0"), "which channel to use")
 87        ("repeat", "repeatedly transmit file")
 88        ("int-n", "tune USRP with integer-n tuning")
 89    ;
 90    // clang-format on
 91    po::variables_map vm;
 92    po::store(po::parse_command_line(argc, argv, desc), vm);
 93    po::notify(vm);
 94
 95    // print the help message
 96    if (vm.count("help")) {
 97        std::cout << boost::format("UHD TX samples from file %s") % desc << std::endl;
 98        return ~0;
 99    }
100
101    bool repeat = vm.count("repeat") > 0;
102
103    // create a usrp device
104    std::cout << std::endl;
105    std::cout << boost::format("Creating the usrp device with: %s...") % args
106              << std::endl;
107    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
108
109    // Lock mboard clocks
110    if (vm.count("ref")) {
111        usrp->set_clock_source(ref);
112    }
113
114    // always select the subdevice first, the channel mapping affects the other settings
115    if (vm.count("subdev"))
116        usrp->set_tx_subdev_spec(subdev);
117
118    std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
119
120    // set the sample rate
121    if (not vm.count("rate")) {
122        std::cerr << "Please specify the sample rate with --rate" << std::endl;
123        return ~0;
124    }
125    std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate / 1e6) << std::endl;
126    usrp->set_tx_rate(rate);
127    std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate() / 1e6)
128              << std::endl
129              << std::endl;
130
131    // set the center frequency
132    if (not vm.count("freq")) {
133        std::cerr << "Please specify the center frequency with --freq" << std::endl;
134        return ~0;
135    }
136    std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq / 1e6) << std::endl;
137    std::cout << boost::format("Setting TX LO Offset: %f MHz...") % (lo_offset / 1e6)
138              << std::endl;
139    uhd::tune_request_t tune_request;
140    tune_request = uhd::tune_request_t(freq, lo_offset);
141    if (vm.count("int-n"))
142        tune_request.args = uhd::device_addr_t("mode_n=integer");
143    usrp->set_tx_freq(tune_request);
144    std::cout << boost::format("Actual TX Freq: %f MHz...") % (usrp->get_tx_freq() / 1e6)
145              << std::endl
146              << std::endl;
147
148    // set the rf gain
149    if (vm.count("gain")) {
150        std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl;
151        usrp->set_tx_gain(gain);
152        std::cout << boost::format("Actual TX Gain: %f dB...") % usrp->get_tx_gain()
153                  << std::endl
154                  << std::endl;
155    }
156
157    // set the analog frontend filter bandwidth
158    if (vm.count("bw")) {
159        std::cout << boost::format("Setting TX Bandwidth: %f MHz...") % (bw / 1e6)
160                  << std::endl;
161        usrp->set_tx_bandwidth(bw);
162        std::cout << boost::format("Actual TX Bandwidth: %f MHz...")
163                         % (usrp->get_tx_bandwidth() / 1e6)
164                  << std::endl
165                  << std::endl;
166    }
167
168    // set the antenna
169    if (vm.count("ant"))
170        usrp->set_tx_antenna(ant);
171
172    // allow for some setup time:
173    std::this_thread::sleep_for(std::chrono::seconds(1));
174
175    // Check Ref and LO Lock detect
176    std::vector<std::string> sensor_names;
177    sensor_names = usrp->get_tx_sensor_names(0);
178    if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked")
179        != sensor_names.end()) {
180        uhd::sensor_value_t lo_locked = usrp->get_tx_sensor("lo_locked", 0);
181        std::cout << boost::format("Checking TX: %s ...") % lo_locked.to_pp_string()
182                  << std::endl;
183        UHD_ASSERT_THROW(lo_locked.to_bool());
184    }
185    sensor_names = usrp->get_mboard_sensor_names(0);
186    if ((ref == "mimo")
187        and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked")
188             != sensor_names.end())) {
189        uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked", 0);
190        std::cout << boost::format("Checking TX: %s ...") % mimo_locked.to_pp_string()
191                  << std::endl;
192        UHD_ASSERT_THROW(mimo_locked.to_bool());
193    }
194    if ((ref == "external")
195        and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked")
196             != sensor_names.end())) {
197        uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked", 0);
198        std::cout << boost::format("Checking TX: %s ...") % ref_locked.to_pp_string()
199                  << std::endl;
200        UHD_ASSERT_THROW(ref_locked.to_bool());
201    }
202
203    // set sigint if user wants to receive
204    if (repeat) {
205        std::signal(SIGINT, &sig_int_handler);
206        std::cout << "Press Ctrl + C to stop streaming..." << std::endl;
207    }
208
209    // create a transmit streamer
210    std::string cpu_format;
211    std::vector<size_t> channel_nums;
212    if (type == "double")
213        cpu_format = "fc64";
214    else if (type == "float")
215        cpu_format = "fc32";
216    else if (type == "short")
217        cpu_format = "sc16";
218    uhd::stream_args_t stream_args(cpu_format, wirefmt);
219    channel_nums.push_back(boost::lexical_cast<size_t>(channel));
220    stream_args.channels             = channel_nums;
221    uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
222
223    // send from file
224    do {
225        if (type == "double")
226            send_from_file<std::complex<double>>(tx_stream, file, spb);
227        else if (type == "float")
228            send_from_file<std::complex<float>>(tx_stream, file, spb);
229        else if (type == "short")
230            send_from_file<std::complex<short>>(tx_stream, file, spb);
231        else
232            throw std::runtime_error("Unknown type " + type);
233
234        if (repeat and delay > 0.0) {
235            std::this_thread::sleep_for(std::chrono::milliseconds(int64_t(delay * 1000)));
236        }
237    } while (repeat and not stop_signal_called);
238
239    // finished
240    std::cout << std::endl << "Done!" << std::endl << std::endl;
241
242    return EXIT_SUCCESS;
243}