Advertisement
Guest User

USRP E312 rx code

a guest
Jan 22nd, 2020
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.51 KB | None | 0 0
  1. #include <uhd/usrp/multi_usrp.hpp>
  2. #include <uhd/utils/safe_main.hpp>
  3. #include <uhd/utils/thread.hpp>
  4. #include <boost/algorithm/string.hpp>
  5. #include <boost/format.hpp>
  6. #include <boost/program_options.hpp>
  7. #include <boost/filesystem.hpp>
  8. #include <chrono>
  9. #include <complex>
  10. #include <iostream>
  11. #include <thread>
  12.  
  13. namespace po = boost::program_options;
  14.  
  15. static bool stop_signal_called = false;
  16. void sig_int_handler(int)
  17. {
  18.   stop_signal_called = true;
  19. }
  20.  
  21. int UHD_SAFE_MAIN(int argc, char* argv[])
  22. {
  23.     // variables to be set by po
  24.     std::string args, sync, path, rx_filename, rx_subdev, rx_channel_list;
  25.     double seconds_in_future;
  26.     size_t rx_nsamps;
  27.     double total_time, rx_rate, rx_freq, rx_gain, rx_bw;
  28.  
  29.     // setup the program options
  30.     po::options_description desc("Allowed options");
  31.     // clang-format off
  32.     desc.add_options()
  33.         ("help", "help message")
  34.         ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
  35.         ("duration", po::value<double>(&total_time)->default_value(60), "Total number of seconds to log data")
  36.         ("delay", po::value<double>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
  37.         ("path", po::value<std::string>(&path)->default_value("/home/root/rx_mqp"), "File path for the log files")
  38.         ("rx_file", po::value<std::string>(&rx_filename)->default_value("rx_data.dat"), "Name of RX log file")
  39.         ("rx_nsamps", po::value<size_t>(&rx_nsamps)->default_value(0), "Total number of RX samples to receive. Set to 0 for continuous")
  40.         ("rx_rate", po::value<double>(&rx_rate)->default_value(0.5e6), "Rate of incoming RX samples")
  41.         ("rx_freq", po::value<double>(&rx_freq)->default_value(900e6), "RF center frequency of RX samples in Hz")
  42.         ("rx_gain", po::value<double>(&rx_gain)->default_value(50), "RX gain for the RF chain")
  43.         ("rx_bw", po::value<double>(&rx_bw)->default_value(200e3), "Analog frontend filter bandwidth of RX samples in Hz")
  44.         ("sync", po::value<std::string>(&sync)->default_value("now"), "synchronization method: now, pps, mimo")
  45.         ("rx_subdev", po::value<std::string>(&rx_subdev)->default_value("0:A"), "RX subdev spec (homogeneous across motherboards)")
  46.         ("rx_channels", po::value<std::string>(&rx_channel_list)->default_value("0,1"), "which RX channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)")
  47.         ("skip-lo", "skip checking LO lock status")
  48.         ("continue", "don't abort on a bad packet")
  49.     ;
  50.     // clang-format on
  51.     po::variables_map vm;
  52.     po::store(po::parse_command_line(argc, argv, desc), vm);
  53.     po::notify(vm);
  54.  
  55.     // print the help message
  56.     if (vm.count("help")) {
  57.         std::cout << boost::format("UHD RX Multi Samples %s") % desc << std::endl;
  58.         std::cout
  59.             << "    This is a demonstration of how to receive aligned data from multiple "
  60.                "channels.\n"
  61.                "    This example can receive from multiple DSPs, multiple motherboards, "
  62.                "or both.\n"
  63.                "    The MIMO cable or PPS can be used to synchronize the configuration. "
  64.                "See --sync\n"
  65.                "\n"
  66.                "    Specify --subdev to select multiple channels per motherboard.\n"
  67.                "      Ex: --subdev=\"0:A 0:B\" to get 2 channels on a Basic RX.\n"
  68.                "\n"
  69.                "    Specify --args to select multiple motherboards in a configuration.\n"
  70.                "      Ex: --args=\"addr0=192.168.10.2, addr1=192.168.10.3\"\n"
  71.             << std::endl;
  72.         return ~0;
  73.     }
  74.  
  75.     bool continue_on_bad_packet = vm.count("continue") > 0;
  76.  
  77.     // create a usrp device
  78.     std::cout << std::endl;
  79.     std::cout << boost::format("Creating the usrp device with: %s...") % args
  80.               << std::endl;
  81.     uhd::usrp::multi_usrp::sptr _usrp = uhd::usrp::multi_usrp::make(args);
  82.  
  83.     // always select the subdevice first, the channel mapping affects the other settings
  84.     if (vm.count("subdev"))
  85.         _usrp->set_rx_subdev_spec(rx_subdev); // sets across all mboards
  86.  
  87.     std::cout << boost::format("Using Device: %s") % _usrp->get_pp_string() << std::endl;
  88.  
  89.     // set the rx sample rate (sets across all channels)
  90.     std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate / 1e6) << std::endl;
  91.     _usrp->set_rx_rate(rx_rate);
  92.     std::cout << boost::format("Actual RX Rate: %f Msps...") % (_usrp->get_rx_rate() / 1e6)
  93.               << std::endl
  94.               << std::endl;
  95.  
  96.     std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
  97.     if (sync == "now") {
  98.         // This is not a true time lock, the devices will be off by a few RTT.
  99.         // Rather, this is just to allow for demonstration of the code below.
  100.         _usrp->set_time_now(uhd::time_spec_t(0.0));
  101.     } else if (sync == "pps") {
  102.         _usrp->set_time_source("external");
  103.         _usrp->set_time_unknown_pps(uhd::time_spec_t(0.0));
  104.         std::this_thread::sleep_for(std::chrono::seconds(1)); // wait for pps sync pulse
  105.     } else if (sync == "mimo") {
  106.         UHD_ASSERT_THROW(_usrp->get_num_mboards() == 2);
  107.  
  108.         // make mboard 1 a slave over the MIMO Cable
  109.         _usrp->set_clock_source("mimo", 1);
  110.         _usrp->set_time_source("mimo", 1);
  111.  
  112.         // set time on the master (mboard 0)
  113.         _usrp->set_time_now(uhd::time_spec_t(0.0), 0);
  114.  
  115.         // sleep a bit while the slave locks its time to the master
  116.         std::this_thread::sleep_for(std::chrono::milliseconds(100));
  117.     }
  118.  
  119.     // detect which channels to use
  120.     std::vector<std::string> channel_strings;
  121.     std::vector<size_t> channel_nums;
  122.     boost::split(channel_strings, rx_channel_list, boost::is_any_of("\"',"));
  123.     for (size_t ch = 0; ch < channel_strings.size(); ch++) {
  124.         size_t chan = std::stoi(channel_strings[ch]);
  125.         if (chan >= _usrp->get_rx_num_channels()) {
  126.             throw std::runtime_error("Invalid channel(s) specified.");
  127.         } else
  128.             channel_nums.push_back(std::stoi(channel_strings[ch]));
  129.     }
  130.  
  131.     for (size_t ch = 0; ch < channel_nums.size(); ch++)
  132.       {
  133.         // set the center frequency
  134.         std::cout << boost::format("rx_init: Channel %d: Setting RX Freq: %f MHz...") % ch % (rx_freq / 1e6)
  135.                   << std::endl;
  136.         uhd::tune_request_t tune_request(rx_freq);
  137.         _usrp->set_rx_freq(tune_request, channel_nums[ch]);
  138.         std::cout << boost::format("rx_init: Channel %d: Actual RX Freq: %f MHz...") % ch % (_usrp->get_rx_freq(channel_nums[ch]) / 1e6)
  139.                   << std::endl
  140.                   << std::endl;
  141.  
  142.         // set the analog frontend filter bandwidth
  143.         std::cout << boost::format("rx_init: Channel %d: Setting RX Bandwidth: %f MHz...") % ch % (rx_bw / 1e6)
  144.                   << std::endl;
  145.         _usrp->set_rx_bandwidth(rx_bw, channel_nums[ch]);
  146.         std::cout << boost::format("rx_init: Channel %d: Actual RX Bandwidth: %f MHz...") % ch % (_usrp->get_rx_bandwidth(channel_nums[ch]) / 1e6)
  147.                   << std::endl
  148.                   << std::endl;
  149.  
  150.         // set the rf gain
  151.         std::cout << boost::format("rx_init: Channel %d: Setting RX Gain: %f dB...") % 0 % rx_gain
  152.                   << std::endl;
  153.         _usrp->set_rx_gain(rx_gain, channel_nums[0]);
  154.         std::cout << boost::format("rx_init: Channel %d: Actual RX Gain: %f dB...") % 0 % _usrp->get_rx_gain(channel_nums[0])
  155.                   << std::endl
  156.                   << std::endl;
  157.  
  158.         // example also sets the antenna here
  159.       }
  160.  
  161.     // create a receive streamer
  162.     // linearly map channels (index0 = channel0, index1 = channel1, ...)
  163.     uhd::stream_args_t stream_args("fc32"); // complex floats
  164.     stream_args.channels             = channel_nums;
  165.     uhd::rx_streamer::sptr rx_stream = _usrp->get_rx_stream(stream_args);
  166.  
  167.     // Setup file path
  168.     std::cout << "main: setup file path" << std::endl;
  169.     boost::filesystem::path out_path;
  170.     out_path = boost::filesystem::path(std::string(path));
  171.     if (!boost::filesystem::exists(out_path))
  172.       boost::filesystem::create_directory(out_path);
  173.     boost::filesystem::path logfile = out_path / boost::filesystem::path(rx_filename);
  174.     std::ofstream outfile(logfile.c_str(), std::ios_base::out);
  175.  
  176.     bool overflow_message = true;
  177.  
  178.     // setup streaming
  179.     std::cout << std::endl;
  180.     std::cout << boost::format("Begin streaming %u samples, %f seconds in the future...")
  181.                      % rx_nsamps % seconds_in_future
  182.               << std::endl;
  183.     uhd::stream_cmd_t stream_cmd((rx_nsamps == 0)
  184.                                      ? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS
  185.                                      : uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
  186.     stream_cmd.num_samps  = rx_nsamps;
  187.     stream_cmd.stream_now = false;
  188.     stream_cmd.time_spec  = uhd::time_spec_t(seconds_in_future);
  189.     rx_stream->issue_stream_cmd(stream_cmd); // tells all channels to stream
  190.  
  191.     // meta-data will be filled in by recv()
  192.     uhd::rx_metadata_t md;
  193.  
  194.     // allocate buffers to receive with samples (one buffer per channel)
  195.     const size_t samps_per_buff = rx_stream->get_max_num_samps();
  196.     std::vector<std::vector<std::complex<float>>> buffs(
  197.         _usrp->get_rx_num_channels(), std::vector<std::complex<float>>(samps_per_buff));
  198.  
  199.     // create a vector of pointers to point to each of the channel buffers
  200.     std::vector<std::complex<float>*> buff_ptrs;
  201.     for (size_t i = 0; i < buffs.size(); i++)
  202.         buff_ptrs.push_back(&buffs[i].front());
  203.  
  204.     // the first call to recv() will block this many seconds before receiving
  205.     double timeout = seconds_in_future + 0.1; // timeout (delay before receive + padding)
  206.  
  207.     size_t num_acc_samps = 0; // number of accumulated samples
  208.     const auto start_time = std::chrono::steady_clock::now();
  209.     const auto stop_time =
  210.         start_time + std::chrono::nanoseconds(int64_t(1e9 * total_time));
  211.  
  212.     while (not stop_signal_called
  213.            and (rx_nsamps > num_acc_samps or rx_nsamps == 0)
  214.            and (total_time == 0.0 or std::chrono::steady_clock::now() <= stop_time)) {
  215.         // receive a single packet
  216.         size_t num_rx_samps = rx_stream->recv(buff_ptrs, samps_per_buff, md, timeout);
  217.  
  218.         // use a small timeout for subsequent packets
  219.         timeout = 0.1;
  220.  
  221.         // handle the error code
  222.         if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) {
  223.             std::cerr << boost::format("Timeout while streaming") << std::endl;
  224.             break;
  225.         }
  226.         if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) {
  227.             if (overflow_message) {
  228.                 overflow_message = false;
  229.                 std::cerr
  230.                     << boost::format(
  231.                            "Got an overflow indication. Please consider the following:\n"
  232.                            "  Your write medium must sustain a rate of %fMB/s.\n"
  233.                            "  Dropped samples will not be written to the file.\n"
  234.                            "  Please modify this example for your purposes.\n"
  235.                            "  This message will not appear again.\n")
  236.                            % (_usrp->get_rx_rate() * sizeof(float) / 1e6);
  237.             }
  238.             continue;
  239.         }
  240.         if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
  241.             std::string error = str(boost::format("Receiver error: %s") % md.strerror());
  242.             if (continue_on_bad_packet) {
  243.                 std::cerr << error << std::endl;
  244.                 continue;
  245.             } else
  246.                 throw std::runtime_error(error);
  247.         }
  248.  
  249.         const auto now = std::chrono::steady_clock::now();
  250.        
  251.         const auto running_time = std::chrono::duration_cast<std::chrono::microseconds>(now - start_time);
  252.         outfile << "\n" << running_time.count() << "\n";
  253.         for (size_t n = 0; n < num_rx_samps; n++)
  254.         {
  255.             std::stringstream ss;
  256.             ss << n;
  257.             for (size_t ch = 0; ch < channel_nums.size(); ch++)
  258.             {
  259.                 float i = buffs[ch][n].real();
  260.                 float q = buffs[ch][n].imag();
  261.  
  262.                 ss << boost::format(",%f,%f") % i % q;
  263.             }
  264.             outfile << ss.str() << "\n";
  265.         }
  266.  
  267.         num_acc_samps += num_rx_samps;
  268.  
  269.     }
  270.  
  271.     if (num_acc_samps < rx_nsamps)
  272.         std::cerr << "Receive timeout before all samples received..." << std::endl;
  273.  
  274.     // finished
  275.     std::cout << std::endl << "Done!" << std::endl << std::endl;
  276.  
  277.     return EXIT_SUCCESS;
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement