The last thread got a little long and kind of died, so I decided to make a new 
thread summarizing all the findings thus far.


I'm running on an x310 across dual 10 Gigabit ethernet, outfitted with twin 
basic tx rx daughbords. I'm running on UHD version 3.11.0. Ideally, I would 
like two simultaneous transmit and receive streams, utilizing both channels to 
transmit and receive. I don't want to have to use 2 x310s for 2 receive and 
transmit streams


When I transmit and receive at the same time on the same channel, I get a lot 
of U's printed out to console signaling underflows, no matter what the rate. 
HOWEVER, if I transmit and receive on separate channels, say tx_streamer has 
stream_args at channel 1 and rx_streamer has stream_args at channel 0, it works 
just fine.


I've attached the source code of a complete but simple program that will 
hopefully demonstrate my problem. In this program, two threads are created: a 
transmit thread and a receive thread. The receive thread is constantly 
receiving data to a buffer and overwriting that buffer with new data. The 
transmit thread is constantly transmitting 0's from a prefilled buffer.


If anyone has an x310 running across 10Gbps ethernet, can you compile and run 
my program to test if this problem occurs not just for me?


Here's what we have already tested:

- I'm running on a server system rocking two 12 core intel xeon processors. 
(https://ark.intel.com/products/91767/Intel-Xeon-Processor-E5-2650-v4-30M-Cache-2_20-GHz).
 My network card is the recommended x520 da2. Someone had previously suggested 
NUMA to be an issue, but I don't think this is the case as the program works 
when we switch to transmitting and receiving on separate channels.


- I've tested only transmitting and only receiving. We can transmit at 200MS/s 
across both channels and we can receive at 200MS/s across both channels, but we 
cannot transmit and receive from the same channel. This suggests our network 
card is working properly and we can handle the high rate.


- I've tried my program on UHD 3.10.2 and the problem still occurs


- I've tried setting the tx_metadata waiting 2 second before transmitting. The 
problem still occurs.


- I've tried running the example program txrx_loopback_from_file and that works 
for simultaneous receive and transmit, but I have no idea why.


>From the last point, I'm lead to believe that I am somehow calling the uhd API 
>wrong, but I have no idea where the error is. Any help would be greatly 
>appreciated.


Thanks,

Jason









#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <vector>
#include <csignal>
#include <boost/date_time.hpp>
#include <boost/thread/thread.hpp>
#include <thread>
//#include <unistd.h>
#include <time.h>

#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/tune_request.hpp>

typedef std::complex<short> Complex;

// Constants and signal variables
static bool stop_signal_called = false;
const int NUM_CHANNELS = 1;
const int BUFF_SIZE = 64000;

//function prototypes here
void recvTask(Complex *buff, uhd::rx_streamer::sptr rx_stream);
void txTask(Complex *buff, uhd::tx_streamer::sptr tx_stream, uhd::tx_metadata_t 
md);
void sig_int_handler(int){
    std::cout << "Interrupt Signal Received" << std::endl;
    stop_signal_called = true;
}

int UHD_SAFE_MAIN(int argc, char *argv[]) {

    uhd::set_thread_priority_safe();

    //type=x300,addr=192.168.30.2,second_addr=192.168.40.2
    std::cout << std::endl;
    std::cout << boost::format("Creating the usrp device") << std::endl;
    uhd::usrp::multi_usrp::sptr usrp = 
uhd::usrp::multi_usrp::make(std::string("type=x300,addr=192.168.30.2,second_addr=192.168.40.2"));
    std::cout << std::endl;

    //set stream args
    uhd::stream_args_t stream_args("sc16"); 

    double samp_rate_tx = 100e6;
    double samp_rate_rx = 100e6;
    uhd::tune_request_t tune_request(0);

    //Lock mboard clocks
    usrp->set_clock_source(std::string("internal"));

    //set rx parameters
    usrp->set_rx_rate(samp_rate_rx);
    usrp->set_rx_freq(tune_request);
    usrp->set_rx_gain(0);

    //set tx parameters
    usrp->set_tx_rate(samp_rate_tx);
    usrp->set_tx_freq(tune_request);
    usrp->set_tx_gain(0);

    std::signal(SIGINT, &sig_int_handler);
    std::cout << "Press Ctrl + C to stop streaming..." << std::endl;

    //create buffers, 2 per channel (1 for tx, 1 for rx)
    // transmitting complex shorts -> typedef as Complex
    Complex *rx_buffs[NUM_CHANNELS];
    Complex *tx_buffs[NUM_CHANNELS];

    for (int i = 0; i < NUM_CHANNELS; i++){
        rx_buffs[i] = new Complex[BUFF_SIZE];
        tx_buffs[i] = new Complex[BUFF_SIZE];
        // only transmitting 0's 
        std::fill(tx_buffs[i], tx_buffs[i]+BUFF_SIZE, 0);
    }

//////////////////////////////////////////////////////////////////////////////
////////////////START RECEIVE AND TRANSMIT THREADS////////////////////////////
//////////////////////////////////////////////////////////////////////////////

    printf("setting up threading\n");

    usrp -> set_time_now(uhd::time_spec_t(0.0));

    // set up RX streams and threads
    std::thread rx_threads[NUM_CHANNELS];
    uhd::rx_streamer::sptr rx_streams[NUM_CHANNELS];
    for (int i = 0; i < NUM_CHANNELS; i++){
        stream_args.channels = std::vector<size_t>(1,i);
        rx_streams[i] = usrp->get_rx_stream(stream_args);
        //setup streaming
        auto stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
        uhd::stream_cmd_t stream_cmd(stream_mode);
        stream_cmd.num_samps = 0;
        stream_cmd.stream_now = true;
        stream_cmd.time_spec = uhd::time_spec_t();
        rx_streams[i]->issue_stream_cmd(stream_cmd);

        //start rx thread
        std::cout << "Starting rx thread " << i << std::endl;
        rx_threads[i] = std::thread(recvTask,rx_buffs[i],rx_streams[i]);
    }


    // set up TX streams and threads
    std::thread tx_threads[NUM_CHANNELS];
    uhd::tx_streamer::sptr tx_streams[NUM_CHANNELS];
    // set up TX metadata
    uhd::tx_metadata_t md;
    md.start_of_burst = true;
    md.end_of_burst = false;
    md.has_time_spec = true;
    md.time_spec = uhd::time_spec_t(0.1); 

    for (int i = 0; i < NUM_CHANNELS; i++){
        //does not work when we transmit and receive on same channel, 
        //if we change to stream_args.channels = std::vector<size_t> (1,1), 
this works for 1 channel.
        stream_args.channels = std::vector<size_t>(1,i);                        
    
        tx_streams[i] = usrp->get_tx_stream(stream_args);
        
        //start the thread
        std::cout << "Starting tx thread " << i << std::endl;
        tx_threads[i] = std::thread(txTask,tx_buffs[i],tx_streams[i],md);
    }

    printf("Waiting to join threads\n");

    for (int i = 0; i < NUM_CHANNELS; i++){
        //join threads
        tx_threads[i].join();
        rx_threads[i].join();
    }
    return EXIT_SUCCESS;
}

void recvTask(Complex *buff, uhd::rx_streamer::sptr rx_stream){
    uhd::rx_metadata_t md;

    size_t num_acc_samps = 0;
    size_t amount_received = 0;
    unsigned overflows = 0;

    struct timespec start_time;
    clock_gettime(CLOCK_MONOTONIC, &start_time);

    //receive loop
    while(!stop_signal_called){
        amount_received = rx_stream->recv(buff,BUFF_SIZE,md,3.0);
        if (amount_received != BUFF_SIZE){ printf("receive not equal\n");}
        //handle the error codes
        switch(md.error_code){
        case uhd::rx_metadata_t::ERROR_CODE_NONE:
            break;

        case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
            std::cerr << "T";
            continue;

        case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
            overflows++;
            std::cerr << "Got an Overflow Indication" << std::endl;
            continue;

        default:
            std::cout << boost::format(
                "Got error code 0x%x, exiting loop..."
            ) % md.error_code << std::endl;
            goto done_loop;
        }
        num_acc_samps += amount_received;
    } done_loop:

    // tell receive to stop streaming
    auto stream_cmd = 
uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
    rx_stream->issue_stream_cmd(stream_cmd);

    // timing stuff
    struct timespec end_time;
    clock_gettime(CLOCK_MONOTONIC, &end_time);
    double runtime = (end_time.tv_sec  - start_time.tv_sec)  +
                     (end_time.tv_nsec - start_time.tv_nsec ) / 1000000000.0;
    std::cout << std::endl << "Received " << num_acc_samps
              << " samples in " << runtime << "s"
              << " Throughput = " << num_acc_samps / 1e6 /runtime << " Msps"
              << std::endl;

    //finished
    std::cout << "Overflows=" << overflows << std::endl << std::endl;
}

void txTask(Complex *buff, uhd::tx_streamer::sptr tx_stream, uhd::tx_metadata_t 
md){

    size_t num_acc_samps = 0;
    struct timespec start_time;
    clock_gettime(CLOCK_MONOTONIC, &start_time);

    //transmit loop
    while(!stop_signal_called){
        size_t samples_sent = tx_stream->send(buff,BUFF_SIZE,md);
        num_acc_samps += samples_sent;

        md.start_of_burst = false;
        md.has_time_spec = false;
    }

    //timing stuff
    struct timespec end_time;
    clock_gettime(CLOCK_MONOTONIC, &end_time);
    double runtime = (end_time.tv_sec  - start_time.tv_sec)  +
                     (end_time.tv_nsec - start_time.tv_nsec ) / 1000000000.0;
    std::cout << std::endl << "Sent " << num_acc_samps
              << " samples in " << runtime << "s"
              << " Throughput = " << num_acc_samps / 1e6 /runtime << " Msps"
              << std::endl;

    //send a mini EOB packet 
    md.end_of_burst = true;
    tx_stream -> send("",0,md);

    printf("End transmit \n");  
}


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

Reply via email to