コード例 #1
0
ファイル: transport_hammer.cpp プロジェクト: Bobakka/uhd
/***********************************************************************
 * 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);
    }
}
コード例 #2
0
ファイル: benchmark_rate.cpp プロジェクト: dkozel/uhd
/***********************************************************************
 * Benchmark TX Rate
 **********************************************************************/
void benchmark_tx_rate(
        uhd::usrp::multi_usrp::sptr usrp,
        const std::string &tx_cpu,
        uhd::tx_streamer::sptr tx_stream,
        std::atomic<bool>& burst_timer_elapsed,
        const boost::posix_time::ptime &start_time,
        bool random_nsamps=false
) {
    uhd::set_thread_priority_safe();

    //print pre-test summary
    std::cout << boost::format(
        "[%s] Testing transmit rate %f Msps on %u channels"
    ) % NOW() % (usrp->get_tx_rate()/1e6) % tx_stream->get_num_channels() << std::endl;

    //setup variables and allocate buffer
    uhd::tx_metadata_t md;
    md.time_spec = usrp->get_time_now() + uhd::time_spec_t(INIT_DELAY);
    md.has_time_spec = (tx_stream->get_num_channels() > 1);
    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<const void *> buffs;
    for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
        buffs.push_back(&buff.front()); //same buffer for each channel
    md.has_time_spec = (buffs.size() != 1);

    if (random_nsamps) {
        std::srand((unsigned int)time(NULL));
        while (not burst_timer_elapsed) {
            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 burst_timer_elapsed) {
            const size_t num_tx_samps_sent_now = tx_stream->send(buffs, max_samps_per_packet, md)*tx_stream->get_num_channels();
            num_tx_samps += num_tx_samps_sent_now;
            if (num_tx_samps_sent_now == 0) {
                num_timeouts_tx++;
                if ((num_timeouts_tx % 10000) == 1) {
                    std::cerr << "[" << NOW() << "] Tx timeouts: " << num_timeouts_tx << std::endl;
                }
            }
            md.has_time_spec = false;
        }
    }

    //send a mini EOB packet
    md.end_of_burst = true;
    tx_stream->send(buffs, 0, md);
}
コード例 #3
0
/***********************************************************************
 * tx_worker function
 * A function to be used in its own thread for transmitting.  Push all
 * tx values into the USRP buffer as USRP buffer space is available,
 * but allow other actions to occur concurrently.
 **********************************************************************/
void tx_worker(
    unsigned int bufflen,
    uhd::tx_streamer::sptr tx_stream,
    uhd::time_spec_t start_time,
    std::complex<int16_t>* vec_ptr,
    int end
){
    unsigned int acc_samps = 0;

    uhd::tx_metadata_t md;
    md.start_of_burst = true;
    md.has_time_spec = true;
    md.time_spec = start_time;

    size_t spb = tx_stream->get_max_num_samps();
    if (spb > bufflen) spb = bufflen;

	while(acc_samps < bufflen-spb){
            size_t nsamples = tx_stream->send(vec_ptr, spb, md);
            vec_ptr += spb;
            acc_samps += nsamples;
            //std::cout << acc_samps <<std::endl;
            md.start_of_burst = false;
            md.has_time_spec = false;
    }
    // Now on the last packet
    if (end) md.end_of_burst = true;
    spb = bufflen - acc_samps;
    size_t nsamples = tx_stream->send(vec_ptr, spb, md);
}
コード例 #4
0
/***********************************************************************
 * Transmit thread
 **********************************************************************/
static void tx_thread(uhd::usrp::multi_usrp::sptr usrp,
    uhd::tx_streamer::sptr tx_stream,
    const double tx_wave_freq,
    const double tx_wave_ampl)
{
    uhd::set_thread_priority_safe();

    // set max TX gain
    usrp->set_tx_gain(usrp->get_tx_gain_range().stop());

    // setup variables and allocate buffer
    uhd::tx_metadata_t md;
    md.has_time_spec = false;
    std::vector<samp_type> buff(tx_stream->get_max_num_samps() * 10);

    // values for the wave table lookup
    size_t index         = 0;
    const double tx_rate = usrp->get_tx_rate();
    const size_t step    = boost::math::iround(wave_table_len * tx_wave_freq / tx_rate);
    wave_table table(tx_wave_ampl);

    // fill buff and send until interrupted
    while (not boost::this_thread::interruption_requested()) {
        for (size_t i = 0; i < buff.size(); i++)
            buff[i] = table(index += step);
        tx_stream->send(&buff.front(), buff.size(), md);
    }

    // send a mini EOB packet
    md.end_of_burst = true;
    tx_stream->send("", 0, md);
}
コード例 #5
0
ファイル: test_messages.cpp プロジェクト: 13572293130/uhd
/*!
 * Test the burst ack message:
 *    Send a burst of many samples that will fragment internally.
 *    We expect to get an burst ack async message.
 */
bool test_burst_ack_message(uhd::usrp::multi_usrp::sptr, uhd::rx_streamer::sptr, uhd::tx_streamer::sptr tx_stream){
    std::cout << "Test burst ack message... " << std::flush;

    uhd::tx_metadata_t md;
    md.start_of_burst = true;
    md.end_of_burst   = true;
    md.has_time_spec  = false;

    //3 times max-sps guarantees a SOB, no burst, and EOB packet
    std::vector<std::complex<float> > buff(tx_stream->get_max_num_samps()*3);

    tx_stream->send(
        &buff.front(), buff.size(), md
    );

    uhd::async_metadata_t async_md;
    if (not tx_stream->recv_async_msg(async_md)){
        std::cout << boost::format(
            "failed:\n"
            "    Async message recv timed out.\n"
        ) << std::endl;
        return false;
    }

    switch(async_md.event_code){
    case uhd::async_metadata_t::EVENT_CODE_BURST_ACK:
        std::cout << boost::format(
            "success:\n"
            "    Got event code burst ack message.\n"
        ) << std::endl;
        return true;

    default:
        std::cout << boost::format(
            "failed:\n"
            "    Got unexpected event code 0x%x.\n"
        ) % async_md.event_code << std::endl;
        return false;
    }
}
コード例 #6
0
int UHD_SAFE_MAIN(int argc, char *argv[]){
    
    uhd::set_thread_priority_safe();    

    std::string args, tx_file, rx_file, type, ref, wire_format, cpu_format;                
    
    double rate, freq, tx_gain, rx_gain, rx_bw, delay, lo_off,seconds_in_future, rx_timeout;

    rx_bw = RX_BW;
    rx_gain = RX_GAIN;
    wire_format = WIRE_FORMAT;
    cpu_format = CPU_FORMAT;
    rate = SAMP_RATE;
    args = ARGS;
    ref = REF_CLOCK;
    freq = CENT_FREQ;
    tx_gain = TX_GAIN;
    // samples_per_buff = SAMPLES_PER_BUFFER;
    tx_file = TX_FILENAME;
    rx_file = RX_FILENAME;
    seconds_in_future = SYNCH_DELAY;
    rx_timeout = RX_TIMEOUT;

    //------------------INIT TX------------------
                                        //Set the scheduling priority on the current thread. Same as set_thread_priority but does not throw on failure.
    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);       //Make the usrp by calling the constructor with param the args

    usrp->set_clock_source(ref);                                          //Set the clock source for the usrp device. This sets the source for a 10 MHz reference clock. Typical options for source: internal, external, MIMO.
    std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl;                           
    usrp->set_tx_rate(rate);                                                                                        //Set the sample rate
    std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl;

    std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq/1e6) << std::endl;                              //Set up tuning frequency
    uhd::tune_request_t tune_request;                                                                               
    tune_request = uhd::tune_request_t(freq);                                                                        //Generate the tune request
    usrp->set_tx_freq(tune_request);                                                                                //Tune to CENT_FREQ
    std::cout << boost::format("Actual TX Freq: %f MHz...") % (usrp->get_tx_freq()/1e6) << std::endl << std::endl;  //PRINT Actual CENT_FREQ

    std::cout << boost::format("Setting TX Gain: %f dB...") % tx_gain << std::endl;                                    
    usrp->set_tx_gain(tx_gain);                                                                                     //Set the tx_gain
    std::cout << boost::format("Actual TX Gain: %f dB...") % usrp->get_tx_gain() << std::endl << std::endl;
    
    //------------------CHECK STUFF------------------
    //Check Ref and LO Lock detect
    std::vector<std::string> sensor_names;
    sensor_names = usrp->get_tx_sensor_names(0);
    if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end()) {
        uhd::sensor_value_t lo_locked = usrp->get_tx_sensor("lo_locked",0);
        std::cout << boost::format("Checking TX: %s ...") % lo_locked.to_pp_string() << std::endl;
        UHD_ASSERT_THROW(lo_locked.to_bool());
    }        



        

    

        
    //------------------INIT RX------------------

    //IS THIS NECESSARY?
    //always select the subdevice first, the channel mapping affects the other settings
    //usrp->set_rx_subdev_spec(subdev);

    std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
    usrp->set_rx_rate(rate);
    std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;

    //set the center frequency
    
    std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << 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;
    
    
    std::cout << boost::format("Setting RX Gain: %f dB...") % rx_gain << std::endl;
    usrp->set_rx_gain(rx_gain);
    std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;    

    boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow 1sec  setup time
    //------------------CHECK STUFF------------------
    
    //Always check for locked sensor
    check_locked_sensor(usrp->get_rx_sensor_names(0), "lo_locked", boost::bind(&uhd::usrp::multi_usrp::get_rx_sensor, usrp, _1, 0), 1);

    //------------------INIT FILES---------------
    

    std::ofstream outfile;    
    outfile.open(rx_file.c_str(), std::ofstream::binary);
    if(!outfile.good()){
        std::cout << "OUT File error\n";
        return 0;
    }

    std::ifstream infile(tx_file.c_str(), std::ifstream::binary);

    if(!infile.good()){
        std::cout << "IN File error\n";
        return 0;
    }

    //------------------INIT STREAMS---------------   

    //Stream ARGS
    uhd::stream_args_t stream_args(cpu_format, wire_format);                //Call the constructor of the class stream_args_t and generate the stream_args object with inputs the cpu_format and wire_format (this is the format per sample)

    tx_stream = usrp->get_tx_stream(stream_args);                           //Generate a tx_streamer object named tx_stream using the usrp->get_tx_stream(stream_args). Remember, usrp is already initialized
    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);    //Generate a tx_streamer object named tx_stream using the usrp->get_tx_stream(stream_args). Remember, usrp is already initialized




    //Setup metadata    

    //Setup tx_metadata

    tx_md.start_of_burst = true;                                              //Set start of burst to true for the first packet in the chain. ?
    tx_md.end_of_burst =   false;        

    #define SYNCHED_TXRX 1
    
    //For TX
    if(SYNCHED_TXRX){
        tx_md.has_time_spec = true;

    }else{
        tx_md.has_time_spec = false;
    }

    //Setup rx_metadata
    uhd::rx_metadata_t rx_md;

    
    //Setup stream command ONLY FOR RX
    uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);        
    stream_cmd.num_samps = samples_per_buff;                            




    //For RX
    if(SYNCHED_TXRX){
        stream_cmd.stream_now = false;                                   
        // tx_md.time_spec =   stream_cmd.time_spec;           
    }else{
        stream_cmd.stream_now = true;                                   
        stream_cmd.time_spec = uhd::time_spec_t();  
    }


    if(SYNCHED_TXRX){
        //Cannt get any faster than this
        tx_md.time_spec = stream_cmd.time_spec = uhd::time_spec_t(seconds_in_future)+usrp->get_time_now();         
    }


    //Create the  buffs    
    
    std::vector<std::complex<float> > small_rx_buff(samples_per_buff);

    
    //Fill the  TX buffer
    for (int i = 0; i < samples_per_buff; ++i){
        
        infile.read((char*)&small_tx_buff.at(i), small_tx_buff.size()*sizeof(std::complex<float>));    

    }    
    infile.close();                                                        //Close the file pointer

    
    //Issue the  stream command
    rx_stream->issue_stream_cmd(stream_cmd);

    //Print number of maximum buffer size
    printf("MAX TX: %d\n", (int)tx_stream->get_max_num_samps());
    printf("MAX RX %d\n", (int)rx_stream->get_max_num_samps());


    size_t num_rx_samps = 0;

    

    boost::thread txThread(thread_startTx);
    
    //receivotrnsmit        
    txThread.join();                        //Strart the thread for tx  (tx is f blocking)
    num_rx_samps = rx_stream->recv(&small_rx_buff.front(), small_rx_buff.size(), rx_md, rx_timeout, false);  // Receive buffers containing samples described by the metadata.    

    // num_rx_samps = rx_stream->recv(&small_rx_buff.front(), small_rx_buff.size(), rx_md, rx_timeout, false);  // Receive buffers containing samples described by the metadata.    


    //Wait for everything to stop
    boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
    
    

    //Cleanup and print what happened
    usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); // Stop the stream (not really necessary here)
    
    double rx_stamp = rx_md.time_spec.get_full_secs() + rx_md.time_spec.get_frac_secs();
    double tx_stamp = tx_md.time_spec.get_full_secs() + tx_md.time_spec.get_frac_secs();
    double t_diff = rx_stamp - tx_stamp;


    printf("RX Time stamp: %.12lf\n ΤX Time stamp: %.12lf\n Diff: %.12lf\n",rx_stamp, tx_stamp, t_diff);
    



    switch ( rx_md.error_code ) {

        case uhd::rx_metadata_t::ERROR_CODE_NONE:
            printf("No error:)\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
            printf("MDError 2\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND:
            printf("MDError 3\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN:
            printf("MDError 4\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
            printf("MDError 5\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_ALIGNMENT:
            printf("MDError 6\n");
            break;
        case uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET:
            printf("MDError 7\n");
            break;

        default:
            printf("WUT\n");
            break;

    }    

    //write the  samples
    if (outfile.is_open()){
        outfile.write((const char*)&small_rx_buff.front(), num_rx_samps*sizeof(std::complex<float>));          
    }



    outfile.close();                                                        //Close the file pointer



    //print
    std::cout << "Transmitted samples: " << num_tx_samps << '\n';
    std::cout << "Received samples: " << num_rx_samps << '\n';




 
    
    return EXIT_SUCCESS;
}
コード例 #7
0
ファイル: UHDDevice.cpp プロジェクト: Djimmer/obts
int uhd_device::open(const std::string &args, bool extref)
{
	// Find UHD devices
	uhd::device_addr_t addr(args);
	uhd::device_addrs_t dev_addrs = uhd::device::find(addr);
	if (dev_addrs.size() == 0) {
		LOG(ALERT) << "No UHD devices found with address '" << args << "'";
		return -1;
	}

	// Use the first found device
	LOG(INFO) << "Using discovered UHD device " << dev_addrs[0].to_string();
	try {
		usrp_dev = uhd::usrp::multi_usrp::make(dev_addrs[0]);
	} catch(...) {
		LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
		return -1;
	}

	// Check for a valid device type and set bus type
	if (!parse_dev_type())
		return -1;

	if (extref)
		set_ref_clk(true);

	// Create TX and RX streamers
	uhd::stream_args_t stream_args("sc16");
	tx_stream = usrp_dev->get_tx_stream(stream_args);
	rx_stream = usrp_dev->get_rx_stream(stream_args);

	// Number of samples per over-the-wire packet
	tx_spp = tx_stream->get_max_num_samps();
	rx_spp = rx_stream->get_max_num_samps();

	// Set rates
	double _tx_rate = select_rate(dev_type, sps);
	double _rx_rate = _tx_rate / sps;
	if ((_tx_rate > 0.0) && (set_rates(_tx_rate, _rx_rate) < 0))
		return -1;

	// Create receive buffer
	size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
	rx_smpl_buf = new smpl_buf(buf_len, rx_rate);

	// Set receive chain sample offset 
	double offset = get_dev_offset(dev_type, sps);
	if (offset == 0.0) {
		LOG(ERR) << "Unsupported configuration, no correction applied";
		ts_offset = 0;
	} else  {
		ts_offset = (TIMESTAMP) (offset * rx_rate);
	}

	// Initialize and shadow gain values 
	init_gains();

	// Print configuration
	LOG(INFO) << "\n" << usrp_dev->get_pp_string();

	switch (dev_type) {
	case B100:
		return RESAMP_64M;
	case USRP2:
	case X3XX:
		return RESAMP_100M;
	}

	return NORMAL;
}
コード例 #8
0
void transceive(
    uhd::usrp::multi_usrp::sptr usrp,
    uhd::tx_streamer::sptr tx_stream,
    uhd::rx_streamer::sptr rx_stream,
    unsigned int npulses,
    float pulse_time,
    //std::complex<int16_t>* txbuff,
    std::vector<std::complex<int16_t> >* txbuff0,
    std::vector<std::complex<int16_t> >* txbuff1,
    float tx_ontime,
    std::complex<int16_t>** outdata,
    size_t samps_per_pulse
){
    int debug = 0;
    if (debug){
        std::cout << "samps_per_pulse: " << samps_per_pulse << std::endl;
    }
    //create metadeta tags for transmit streams
    uhd::time_spec_t start_time = usrp->get_time_now() + 0.05;
    uhd::tx_metadata_t md;
    md.start_of_burst = true;
    md.end_of_burst = false;
    md.has_time_spec = true;
    md.time_spec = start_time;
    std::vector<std::complex<int16_t> *> vec_ptr;
    vec_ptr.resize(1);
    //vec_ptr[0] = &txbuff->front();
    
    usrp->set_gpio_attr("RXA","CTRL",0x0, TR_BIT); //GPIO mode
    usrp->set_gpio_attr("RXA","DDR",TR_BIT, TR_BIT); //Direction out
    
    //create metadata tags for receive stream
    uhd::rx_metadata_t rxmd;
    std::vector<std::complex<int16_t> > buff(samps_per_pulse,0);
    if (verbose) std::cout << "rx buff size: " << buff.size() << std::endl;
    if (verbose) std::cout << "tx buff size: " << txbuff0->size() << std::endl;
    uhd::stream_cmd_t stream_cmd = uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE;
    stream_cmd.num_samps = npulses*samps_per_pulse;
    stream_cmd.stream_now = false;
    stream_cmd.time_spec = start_time + 22 / usrp->get_rx_rate(); //Digital hardware delay is 22 samples long.  Found by experiment.
    if (verbose) std::cout << "time spec: " << stream_cmd.time_spec.get_real_secs() << std::endl;
    
    //loop for every pulse in the sequence
    size_t spb;
    std::vector<std::complex<int16_t>* > rx_dptr;
    rx_dptr.resize(usrp->get_rx_num_channels());
    spb = tx_stream->get_max_num_samps();
    if (verbose) std::cout << "npulses: " << npulses << std::endl;
    boost::thread_group rx_threads;
    boost::thread_group tx_threads;
    for (int ipulse=0; ipulse<npulses; ipulse++){
        if (debug) std::cout << "pulse number: " << ipulse << std::endl;
        for (size_t ichan=0; ichan<usrp->get_rx_num_channels(); ichan++){
         rx_dptr[ichan] = ipulse*samps_per_pulse + outdata[ichan];
        }
        
        float timeout = 1.1;
        
        //usrp->set_command_time(start_time-50e-6,0);
        //usrp->set_gpio_attr("RXA","OUT",TR_BIT, TR_BIT);
        
        if (ipulse==0){
            if (verbose) std::cout << "time spec: " << stream_cmd.time_spec.get_real_secs() << std::endl;
            if (verbose) std::cout << "Issuing stream command to start collecting samples\n";
            usrp->issue_stream_cmd(stream_cmd);
        }
        
        //usrp->set_command_time(start_time+tx_ontime,0);
        //usrp->set_gpio_attr("RXA","OUT",0x0, TR_BIT);
        
        size_t acc_samps=0;
        if (ipulse%2 == 0) {
            vec_ptr[0] = &txbuff0->front();
        }
        if (ipulse%2 == 1) {
            vec_ptr[0] = &txbuff1->front();
        }
        
        if (ipulse != npulses-1) {
             tx_threads.create_thread(boost::bind(tx_worker,
                 txbuff0->size(), tx_stream, start_time, vec_ptr[0], 0));
        }
        if (ipulse == npulses-1) {
             tx_threads.create_thread(boost::bind(tx_worker,
                 txbuff0->size(), tx_stream, start_time, vec_ptr[0], 1));
        }
        
        rx_threads.join_all();
        rx_threads.create_thread(boost::bind(rx_worker,
         rx_stream, samps_per_pulse, rx_dptr));
        
        //for (int k=0; k<10; k++){
        // //std::cout << "raw data: " << outdata[0][i][k] << "\t" << outdata[1][i][k] << std::endl;
        // std::cout << "raw data: " << rx_dptr[0][k] << " " << rx_dptr[1][k] << std::endl;
        //}
        //for (int k=0; k<samps_per_pulse; k++)
        //    outdata[i][k] += buff[k];
        
        
        start_time += float(pulse_time);
    }
    tx_threads.join_all();
    rx_threads.join_all();
}