Using similar code, but with the addition of the DmaFIFO to the chain, I
have created the attached source code.  Additionally, I have attached a
"log" file which shows the command line parameters as well as the response
for an individual run.  I have a few remarks:

   - In general, the code works in that I can repetitively stream the
   desired waveform file and it looks as expected on a signal analyzer.
   However, it is not well optimized such that when I increase the streaming
   rate to 100 MS/s, I get errors (and sometimes see a couple of issues at 50
   MS/s.
   - In the log file, you will find some "L" and many "U".  This was
   actually a "good" run.  In additional runs, there were many more "U" that
   continued throughout the run
   - If instead of this rfnoc tx example, I use a multi_usrp object to
   handle the details of connecting the blocks and streaming the data, I have
   no problems (no "L" or "U"), even at 100 MS/s
   - So, it seems clear to me that I have not connected / configured the
   blocks optimally

Here are my questions:

   - What am I doing wrong that is causing the sub-optimal streaming?
   - Why do I get the following warnings?  Could this explain the
   sub-optimal streaming?  What is the correct way to configure SPP for each
   block or connection?
      - [WARNING] [RFNOC] Assuming max packet size for 0/DmaFIFO_0
      - [WARNING] [RFNOC] Assuming max packet size for 0/DUC_0
   - Why do I get the following error message upon program termination?
      - AssertionError: [0/DmaFIFO_0] Attempting to disconnect input port
      0, which is not registered as connected!

Thanks for any help.
Rob


On Thu, Sep 20, 2018 at 7:22 PM Ryan Marlow via USRP-users <
usrp-users@lists.ettus.com> wrote:

> Hey Leo,
> Glad to hear you were able to work things out. One quick note about the
> code I attached previously. Located a minor typo/bug that you'll want to
> fix if you want to actually transmit useful data.
>
>> 219         radio_ctrl->set_rx_frequency(freq, radio_chan);
>>
> should be:
>
>> 219         radio_ctrl->set_tx_frequency(freq, radio_chan);
>>
> Notice the change from rx->tx.
> Best,
> Ryan Marlow
>
>
> On Thu, Sep 20, 2018 at 10:35 AM, Leandro Echevarría <
> leoechevar...@gmail.com> wrote:
>
>> Hey Ryan,
>>
>> Thanks a lot! I actually ended up doing pretty much the exact same things
>> you described, and came up with a piece of code very similar to yours.
>> Yours is neater though, so I will keep it ;-).
>>
>> Regards,
>>
>> Leo
>>
>> On Wed, Sep 19, 2018 at 7:52 PM Ryan Marlow <r...@lmarlow.com> wrote:
>>
>>> Hey Leo,
>>> I haven't seen anyone respond yet and I recently needed to develop a TX
>>> RFNoC example of my own. I worked off the rfnoc_rx_to_file.cpp example. Far
>>> from perfect, but it gets the job done (transmits data). The main changes
>>> are:
>>> - copied send_from_file function from tx_samples_from_file.cpp example
>>> to handle the streaming of data from the input file
>>> - reversed the order that blocks are connected in the graph->connect()
>>> function. Now connects optional arg block -> radio. Was radio -> optional
>>> arg block.
>>> - uses tx_stream instead of rx_stream.
>>> Just add this cpp file to the CMake file in the host/examples dir to
>>> build it then try it out.
>>> I ran it with:
>>> build/examples$ ./rfnoc_tx_from_file --block-id DUC_0 --block-args
>>> output_rate=200e6,input_rate=5e6 --duration 5 --file usrp_samples.dat
>>>
>>> Hope that helps,
>>> Ryan
>>> --
>>> Ryan L. Marlow
>>> R L Marlow Consulting LLC
>>> rlmarlow.com
>>>
>>
>
>
> --
> Ryan L. Marlow
> R L Marlow Consulting LLC
> rlmarlow.com
> _______________________________________________
> USRP-users mailing list
> USRP-users@lists.ettus.com
> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
>
$ ./rfnoc_tx_samples_from_file --file=$HOME/Documents/waveforms/mtone_100_0p8_0_le.bin --freq=2400e6 --rate=100e6 --gain=0
Creating the USRP device with: . . .

[INFO] [UHD] linux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_3.13.0.3-0-g85347b89
[INFO] [X300] X300 initialization sequence...
[INFO] [X300] Maximum frame size: 8000 bytes.
[INFO] [X300] Radio 1x clock: 200 MHz
[INFO] [0/DmaFIFO_0] Initializing block control (NOC ID: 0xF1F0D00000000000)
[INFO] [0/DmaFIFO_0] BIST passed (Throughput: 1309 MB/s)
[INFO] [0/DmaFIFO_0] BIST passed (Throughput: 1298 MB/s)
[INFO] [0/Radio_0] Initializing block control (NOC ID: 0x12AD100000000001)
[INFO] [0/Radio_1] Initializing block control (NOC ID: 0x12AD100000000001)
[INFO] [0/DDC_0] Initializing block control (NOC ID: 0xDDC0000000000000)
[INFO] [0/DDC_1] Initializing block control (NOC ID: 0xDDC0000000000000)
[INFO] [0/DUC_0] Initializing block control (NOC ID: 0xD0C0000000000000)
[INFO] [0/DUC_1] Initializing block control (NOC ID: 0xD0C0000000000000)
Using radio 0, channel 0
Using duc 0, channel 0
Using FIFO 0, channel 0
Setting TX Freq: 2400.000000 MHz...
Actual TX Freq: 2400.000000 MHz...

Setting TX Rate: 100.000000 Msps...
DUC input rate: 100 MS/s; DUC output rate: 200 MS/s

Setting TX Gain: 0.000000 dB...
Actual TX Gain: 0.000000 dB...

Using streamer args: block_id=0/DmaFIFO_0,block_port=0
Connecting...
   0/DmaFIFO_0 ==> 0/DUC_0
[WARNING] [RFNOC] Assuming max packet size for 0/DmaFIFO_0
   0/DUC_0 ==> 0/Radio_0

[WARNING] [RFNOC] Assuming max packet size for 0/DUC_0
Start streaming...
Replaying data (Press Ctrl+C to stop)...
LLLUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU^C
Streaming stopped
terminate called after throwing an instance of 'uhd::assertion_error'
  what():  AssertionError: [0/DmaFIFO_0] Attempting to disconnect input port 0, which is not registered as connected!
Aborted (core dumped)
$ 

//
// Copyright 2018 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Description:
//
// This example demonstrates using the rfnoc blocks to play data from a file.

#include <uhd/utils/safe_main.hpp>
#include <uhd/device3.hpp>
#include <uhd/rfnoc/radio_ctrl.hpp>
#include <uhd/rfnoc/duc_block_ctrl.hpp>
#include <uhd/rfnoc/block_ctrl.hpp>
#include <uhd/utils/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <fstream>
#include <csignal>
#include <thread>

namespace po = boost::program_options;

using std::cout;
using std::endl;


///////////////////////////////////////////////////////////////////////////////

static volatile bool stop_signal_called = false;

// Ctrl+C handler
void sig_int_handler(int)
{
	stop_signal_called = true;
}


int UHD_SAFE_MAIN(int argc, char *argv[])
{
	uhd::set_thread_priority_safe();

	// We use sc16 in this example, but the replay block only uses 64-bit words
	// and is not aware of the CPU or wire format.
	std::string wire_format("sc16");
	std::string cpu_format("sc16");


	///////////////////////////////////////////////////////////////////////////
	// Handle command line options

	std::string args, radio_args, file, ant, ref;
	double rate, freq, gain, bw;
	size_t radio_id, radio_chan, duc_id, duc_chan, fifo_id, fifo_chan, nsamps;

	po::options_description desc("Allowed Options");
	desc.add_options()
	("help", "help message")
	("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
	("radio-id", po::value<size_t>(&radio_id)->default_value(0), "radio block to use (e.g., 0 or 1).")
	("radio-chan", po::value<size_t>(&radio_chan)->default_value(0), "radio channel to use")
	("radio-args", po::value<std::string>(&radio_args), "radio arguments")
	("duc-id", po::value<size_t>(&duc_id)->default_value(0), "duc block to use (e.g., 0 or 1)")
	("duc-chan", po::value<size_t>(&duc_chan)->default_value(0), "duc channel to use")
	("fifo-id", po::value<size_t>(&fifo_id)->default_value(0), "fifo block to use (e.g., 0 or 1).")
	("fifo-chan", po::value<size_t>(&fifo_chan)->default_value(0), "fifo channel to use")
	("nsamps", po::value<uint64_t>(&nsamps)->default_value(0), "number of samples to play (0 for infinite)")
	("file", po::value<std::string>(&file)->default_value("usrp_samples.dat"), "name of the file to read binary samples from")
	("freq", po::value<double>(&freq), "RF center frequency in Hz")
	("rate", po::value<double>(&rate), "sample rate of host->usrp streaming")
	("gain", po::value<double>(&gain), "gain for the RF chain")
	("ant", po::value<std::string>(&ant), "antenna selection")
	("bw", po::value<double>(&bw), "analog front-end filter bandwidth in Hz")
	("ref", po::value<std::string>(&ref)->default_value("internal"), "reference source (internal, external, mimo)")
	;
	po::variables_map vm;
	po::store(po::parse_command_line(argc, argv, desc), vm);
	po::notify(vm);

	// Print help message
	if (vm.count("help")) {
		cout << boost::format("UHD/RFNoC Replay samples from file %s") % desc << endl;
		cout
		    << "This application uses the Replay block to playback data from a file to a radio" << endl
		    << endl;
		return EXIT_FAILURE;
	}


	///////////////////////////////////////////////////////////////////////////
	// Create USRP device and block controls

	cout << "Creating the USRP device with: " << args << ". . .\n" << endl;
	uhd::device3::sptr usrp = uhd::device3::make(args);

	// Create handle for radio object
	uhd::rfnoc::block_id_t radio_ctrl_id(0, "Radio", radio_id);
	uhd::rfnoc::radio_ctrl::sptr radio_ctrl;
	radio_ctrl = usrp->get_block_ctrl<uhd::rfnoc::radio_ctrl>(radio_ctrl_id);
	std::cout << "Using radio " << radio_id << ", channel " << radio_chan << std::endl;

	// Create handle for digital upconverter object
	uhd::rfnoc::block_id_t duc_ctrl_id(0, "DUC", duc_id);
	uhd::rfnoc::duc_block_ctrl::sptr duc_ctrl;
	duc_ctrl = usrp->get_block_ctrl<uhd::rfnoc::duc_block_ctrl>(duc_ctrl_id);
	std::cout << "Using duc " << duc_id << ", channel " << duc_chan << std::endl;

	// Create handle for DmaFIFO
	uhd::rfnoc::block_id_t fifo_ctrl_id(0, "DmaFIFO", fifo_id);
	uhd::rfnoc::block_ctrl_base::sptr fifo_ctrl;
	fifo_ctrl = usrp->get_block_ctrl<uhd::rfnoc::block_ctrl_base>(fifo_ctrl_id);
	std::cout << "Using FIFO " << fifo_id << ", channel " << fifo_chan << std::endl;


	///////////////////////////////////////////////////////////////////////////
	// Configure radio and DUC

	// Lock clocks
	radio_ctrl->set_clock_source(ref);

	// Apply any radio arguments provided
	radio_ctrl->set_args(radio_args);

	// Set the center frequency
	if (not vm.count("freq")) {
		std::cerr << "Please specify the center frequency with --freq" << std::endl;
		return EXIT_FAILURE;
	}
	std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq/1e6) << std::endl;
	radio_ctrl->set_tx_frequency(freq, radio_chan);
	std::cout << boost::format("Actual TX Freq: %f MHz...") % (radio_ctrl->get_tx_frequency(radio_chan)/1e6) << std::endl << std::endl;

	// Set the sample rate
	if (vm.count("rate")) {
		std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl;
		//radio_ctrl->set_rate(rate);
		duc_ctrl->set_arg("input_rate",rate,duc_chan);
		duc_ctrl->set_arg("output_rate",radio_ctrl->get_rate(),duc_chan);
		std::cout << "DUC input rate: " << duc_ctrl->get_arg<double>("input_rate",duc_chan)/1e6 <<
		          " MS/s; DUC output rate: " << duc_ctrl->get_arg<double>("output_rate",duc_chan)/1e6 <<
		          " MS/s" << std::endl << std::endl;
	}

	// Set the RF gain
	if (vm.count("gain")) {
		std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl;
		radio_ctrl->set_tx_gain(gain, radio_chan);
		std::cout << boost::format("Actual TX Gain: %f dB...") % radio_ctrl->get_tx_gain(radio_chan) << std::endl << std::endl;
	}

	// Set the analog front-end filter bandwidth
	if (vm.count("bw")) {
		std::cout << boost::format("Setting TX Bandwidth: %f MHz...")
		          % (bw / 1e6)
		          << std::endl;
		radio_ctrl->set_tx_bandwidth(bw, radio_chan);
		std::cout << boost::format("Actual TX Bandwidth: %f MHz...")
		          % (radio_ctrl->get_tx_bandwidth(radio_chan) / 1e6)
		          << std::endl << std::endl;
	}

	// Set the antenna
	if (vm.count("ant")) {
		radio_ctrl->set_tx_antenna(ant, radio_chan);
	}

	// Allow for some setup time
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));


	///////////////////////////////////////////////////////////////////////////
	// Setup streamer to DUC block

	uhd::device_addr_t streamer_args;
	uhd::stream_args_t stream_args(cpu_format, wire_format);
	uhd::tx_streamer::sptr tx_stream;

	streamer_args["block_id"] = fifo_ctrl->get_block_id().to_string();
	streamer_args["block_port"] = str(boost::format("%d") % fifo_chan);
	stream_args.args = streamer_args;
	tx_stream = usrp->get_tx_stream(stream_args);
	//const size_t tx_spb = tx_stream->get_max_num_samps();

	cout << "Using streamer args: " << stream_args.args.to_string() << endl;


	///////////////////////////////////////////////////////////////////////////
	// Connect DmaFIFO->DUC->Radio

	uhd::rfnoc::graph::sptr tx_graph = usrp->create_graph("rfnoc_tx");
	usrp->clear();
	//int radio_spp = tx_spb;
	std::cout << "Connecting..." << std::endl;

	std::cout << "   " << fifo_ctrl->get_block_id() << " ==> " << duc_ctrl->get_block_id() << std::endl;
	tx_graph->connect(fifo_ctrl->get_block_id(), fifo_chan, duc_ctrl->get_block_id(), duc_chan);

	std::cout << "   " << duc_ctrl->get_block_id() << " ==> " << radio_ctrl->get_block_id() << std::endl << std::endl;
	tx_graph->connect(duc_ctrl->get_block_id(), duc_chan, radio_ctrl->get_block_id(), radio_chan);


	///////////////////////////////////////////////////////////////////////////
	// Read the data to replay

	// Open the file
	std::ifstream infile(file.c_str(), std::ifstream::binary);
	if (!infile.is_open()) {
		std::cerr << "Could not open specified file" << std::endl;
		return EXIT_FAILURE;
	}

	// Get the file size
	infile.seekg(0, std::ios::end);
	size_t file_size = infile.tellg();

	int num_samps = file_size / 4;

	// Create buffer
	std::vector<char> tx_buffer(num_samps*4);
	char* tx_buf_ptr = &tx_buffer[0];

	// Read file into buffer, rounded down to number of words
	infile.seekg(0, std::ios::beg);
	infile.read(tx_buf_ptr, num_samps*4);
	infile.close();


	///////////////////////////////////////////////////////////////////////////
	// Stream the data
	cout << "Start streaming..." << endl;
	uhd::tx_metadata_t tx_md;
	tx_md.start_of_burst = true;
	tx_md.end_of_burst   = false;
	tx_md.has_time_spec = true;
	tx_md.time_spec = radio_ctrl->get_time_now() + uhd::time_spec_t(1.0);

	///////////////////////////////////////////////////////////////////////////
	// Wait until user says to stop

	// Setup SIGINT handler (Ctrl+C)
	stop_signal_called = false;
	std::signal(SIGINT, &sig_int_handler);
	cout << "Replaying data (Press Ctrl+C to stop)..." << endl;

	while (not stop_signal_called) {
		size_t num_tx_samps = tx_stream->send(tx_buf_ptr, num_samps, tx_md);
		//std::cout << "samps sent: " << num_tx_samps << std::endl;
		tx_md.start_of_burst = false;
		tx_md.has_time_spec = false;

		if (num_tx_samps != num_samps) {
			cout << boost::format("ERROR: Unable to send %d samples") % num_samps << endl;
			return EXIT_FAILURE;
		}
	}
	// Remove SIGINT handler
	std::signal(SIGINT, SIG_DFL);

	// send one more buffer with end-of-burst true
	tx_md.end_of_burst   = true;
	tx_stream->send(tx_buf_ptr, num_samps, tx_md);

	std::cout << std::endl << "Streaming stopped" << std::endl;

	std::this_thread::sleep_for(std::chrono::milliseconds(1000));

	return EXIT_SUCCESS;
}
_______________________________________________
USRP-users mailing list
USRP-users@lists.ettus.com
http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com

Reply via email to