/*********************************************************************** * 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); } }
/*********************************************************************** * 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); }
/*********************************************************************** * 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); }
/*********************************************************************** * 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); }
/*! * 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; } }
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; }
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; }
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(); }