void get_rx_parameters(uhd::usrp::multi_usrp::sptr usrp, size_t mboard , std::ostream & os) { using namespace std; namespace radio = uhd::usrp; size_t nchan = 0; // Get sub device specification os << std::endl << "********** RX Sub Device ***********" << std::endl; os << std::endl << "-----> Get Rx Subdevice" << std::endl; radio::subdev_spec_t rx_subdev = usrp->get_rx_subdev_spec(mboard); os << "RX Subdevice Specification:" << endl; os << rx_subdev.to_pp_string() << endl; os << std::endl << "-----> Get number of RX channels" << std::endl; size_t num_rx = usrp->get_rx_num_channels(); os << "Number of RX channels:" << endl; os << num_rx << endl; os << std::endl << "-----> Get RX Subdevice Name" << std::endl; string rx_name = usrp->get_rx_subdev_name(nchan); os << "RX Subdevice Name:" << endl; os << rx_name << endl; os << std::endl << "********** RX Sample Rate ***********" << std::endl; os << std::endl << "-----> Get RX Rate" << std::endl; double rx_rate = usrp->get_rx_rate(nchan); os << "RX Rate:" << endl; os << rx_rate << endl; os << std::endl << "-----> Get RX Rate List" << std::endl; uhd::meta_range_t rx_rates = usrp->get_rx_rates(nchan); os << "RX Rate List:" << endl; os << "Start: " << rx_rates.start() << " Stop: " << rx_rates.stop() << " Step: " << rx_rates.step() << endl; os << rx_rates.to_pp_string() << endl; // RX FREQUENCIES os << std::endl << "********** RX Frequencies ***********" << std::endl; os << std::endl << "-----> Get RX Center Frequency" << std::endl; double rx_freq = usrp->get_rx_freq(nchan); os << "RX Freq:" << endl; os << rx_freq << endl; os << std::endl << "-----> Get RX Center Frequency Range" << std::endl; uhd::freq_range_t rx_freq_range = usrp->get_rx_freq_range(nchan); os << "RX Frequency Range:" << endl; os << "Start: " << rx_freq_range.start() << " Stop: " << rx_freq_range.stop() << " Step: " << rx_freq_range.step() << endl; os << rx_freq_range.to_pp_string() << endl; // RX Front end frequencies os << std::endl << "-----> Get RX RF Front End Center Frequency Range" << std::endl; try { os << "RX Front End Frequency Range:" << endl; uhd::freq_range_t rx_fe_freq_range = usrp->get_fe_rx_freq_range(nchan); os << "Start: " << rx_fe_freq_range.start() << " Stop: " << rx_fe_freq_range.stop() << " Step: " << rx_fe_freq_range.step() << endl; os << rx_fe_freq_range.to_pp_string() << endl; } catch (uhd::runtime_error &e) { os << " Exception occurred : " << e.code() << endl; } // RX GAIN os << std::endl << "********** RX Gain ***********" << std::endl; // Total combined gain os << endl << "-----> Get RX Total Gain" << endl; os << "RX Total Gain: " ; try { double rx_total_gain = usrp->get_rx_gain(nchan); os << rx_total_gain << endl; } catch(uhd::runtime_error &e) { os << "Exception code: " << e.code() << endl; } // List of all gain elements os << std::endl << "-----> Get RX gain names" << std::endl; std::vector<std::string> rx_gain_names = usrp->get_rx_gain_names(nchan); os << "Rx Gain Names: " << std::endl; for (int index =0; index < rx_gain_names.size(); index++) { // Name os << "\t" << rx_gain_names[index] << endl; } for (int index =0; index < rx_gain_names.size(); index++) { // Name os << "\t" << "Name: " << rx_gain_names[index] << " Value: "; // Value try { double element_gain = usrp->get_rx_gain(rx_gain_names[index], nchan); os << element_gain << endl; } catch(uhd::runtime_error &e) { os << "Exception code while getting value: " << e.code() << endl; } } // Gain ranges for each of the gain elements os << std::endl << "-----> Get RX element gain ranges" << std::endl; for (int index =0; index < rx_gain_names.size(); index++) { // Name os << "\t" << "Name: " << rx_gain_names[index] << " Value: "; // Value try { uhd::gain_range_t element_gain_range = usrp->get_rx_gain_range(rx_gain_names[index], nchan); os << "Start: " << element_gain_range.start() << " End: " << element_gain_range.stop() << " Step: " << element_gain_range.step() << endl; } catch(uhd::runtime_error &e) { os << "Exception code while getting value: " << e.code() << endl; } } // Total Gain range try { os << endl << "-----> Get RX Total Gain Range" << endl; uhd::gain_range_t rx_total_gain_range = usrp->get_rx_gain_range(nchan); os << "RX Total Gain Range: " ; os << "Start: " << rx_total_gain_range.start() << " End: " << rx_total_gain_range.stop() << " Step: " << rx_total_gain_range.step() << endl; } catch(uhd::runtime_error &e) { os << "Exception code: " << e.code() <<endl; } // ANTENNA FUNCTIONS os << std::endl << "********** RX ANTENNA ***********" << std::endl; // Current Rx Antenna os << std::endl << "-----> Get RX Antenna" << std::endl; string rx_antenna = usrp->get_rx_antenna(nchan); os << "RX Antenna: " ; os << rx_antenna << endl; // RX Antenna choices os << std::endl << "-----> Get Rx Antenna List" << std::endl; std::vector<std::string> rx_antennas = usrp->get_rx_antennas(nchan); os << "RX Antennas : " << std::endl; for (int index =0; index < rx_antennas.size(); index++) os << "\t" << rx_antennas[index] << std::endl; // RX BANDWIDTH FUNCTIONS os << std::endl << "********** RX BANDWIDTH ***********" << std::endl; // Current RX Bandwidth os << endl << "-----> Get RX Bandwidth" << endl; try { os << "RX Bandwidth " ; double rx_bandwidth = usrp->get_rx_bandwidth(nchan); os << rx_bandwidth << endl; } catch (uhd::runtime_error &e) { os << "Exception occured " << e.code() << endl; } // RX Bandwidth Range os << endl << "-----> Get RX Bandwidth Range" << endl; try { os << "RX Bandwidth Range: " ; uhd::gain_range_t rx_bandwidth_range = usrp->get_rx_bandwidth_range(nchan); os << "Start: " << rx_bandwidth_range .start() << " End: " << rx_bandwidth_range .stop() << " Step: " << rx_bandwidth_range .step() << endl; } catch(uhd::runtime_error &e) { os << "Exception code: " << e.code() <<endl; } // RX DBOARD INTERFACE OBJECT os << std::endl << "********** RX DBOARD INTERFACE ***********" << std::endl; // RX Dboard Interface os << endl << "-----> Get rx_dboard_iface()" << endl; try { os << "RX Dboard Interface " ; uhd::usrp::dboard_iface::sptr rx_dboard_iface = usrp->get_rx_dboard_iface(nchan); os << rx_dboard_iface << endl; } catch (uhd::runtime_error &e) { os << "Exception occured " << e.code() << endl; } // RX _SENSORS os << std::endl << "********** RX Sensors ***********" << std::endl; // List of all available sensors os << std::endl << "-----> Get RX Sensors Name" << std::endl; std::vector<std::string> rx_sensor_names = usrp->get_rx_sensor_names(nchan); os << "Sensor Names: " << std::endl; for (int index =0; index < rx_sensor_names.size(); index++) { // Name os << "\t" << rx_sensor_names[index] << ": "; // Value try { uhd::sensor_value_t rx_sensor_value = usrp->get_rx_sensor(rx_sensor_names[index], nchan); os << rx_sensor_value.to_pp_string()<< std::endl; } catch(uhd::runtime_error &e) { os << "Exception occured " << e.code() << endl; } } }
/*********************************************************************** * RX Hammer **********************************************************************/ void rx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, const std::string &rx_otw){ uhd::set_thread_priority_safe(); //create a receive streamer uhd::stream_args_t stream_args(rx_cpu, rx_otw); for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping stream_args.channels.push_back(ch); uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //print pre-test summary std::cout << boost::format( "Testing receive rate %f Msps" ) % (usrp->get_rx_rate()/1e6) << std::endl; //setup variables and allocate buffer uhd::rx_metadata_t md; const size_t max_samps_per_packet = rx_stream->get_max_num_samps(); std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(rx_cpu)); std::vector<void *> buffs; for (size_t ch = 0; ch < stream_args.channels.size(); ch++) buffs.push_back(&buff.front()); //same buffer for each channel bool had_an_overflow = false; uhd::time_spec_t last_time; const double rate = usrp->get_rx_rate(); double timeout = 1; uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(0.05); cmd.stream_now = (buffs.size() == 1); srand( time(NULL) ); while (not boost::this_thread::interruption_requested()){ cmd.num_samps = rand() % 100000; usrp->issue_stream_cmd(cmd); num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md, timeout, true); //handle the error codes switch(md.error_code){ case uhd::rx_metadata_t::ERROR_CODE_NONE: if (had_an_overflow){ had_an_overflow = false; num_dropped_samps += boost::math::iround((md.time_spec - last_time).get_real_secs()*rate); } break; case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: had_an_overflow = true; last_time = md.time_spec; num_overflows++; break; default: std::cerr << "Error code: " << md.error_code << std::endl; std::cerr << "Unexpected error on recv, continuing..." << std::endl; break; } } }
int uhd_device::set_rates(double tx_rate, double rx_rate) { double offset_limit = 1.0; double tx_offset, rx_offset; // B2XX is the only device where we set FPGA clocking if (dev_type == B2XX) { if (set_master_clk(B2XX_CLK_RT) < 0) return -1; } // Set sample rates try { usrp_dev->set_tx_rate(tx_rate); usrp_dev->set_rx_rate(rx_rate); } catch (const std::exception &ex) { LOG(ALERT) << "UHD rate setting failed"; LOG(ALERT) << ex.what(); return -1; } this->tx_rate = usrp_dev->get_tx_rate(); this->rx_rate = usrp_dev->get_rx_rate(); tx_offset = fabs(this->tx_rate - tx_rate); rx_offset = fabs(this->rx_rate - rx_rate); if ((tx_offset > offset_limit) || (rx_offset > offset_limit)) { LOG(ALERT) << "Actual sample rate differs from desired rate"; LOG(ALERT) << "Tx/Rx (" << this->tx_rate << "/" << this->rx_rate << ")"; return -1; } return 0; }
/*********************************************************************** * Data capture routine **********************************************************************/ static void capture_samples( uhd::usrp::multi_usrp::sptr usrp, uhd::rx_streamer::sptr rx_stream, std::vector<samp_type > &buff, const size_t nsamps_requested) { buff.resize(nsamps_requested); uhd::rx_metadata_t md; // Right after the stream is started, there will be transient data. // That transient data is discarded and only "good" samples are returned. size_t nsamps_to_discard = size_t(usrp->get_rx_rate() * 0.001); // 1ms to be discarded std::vector<samp_type> discard_buff(nsamps_to_discard); uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); stream_cmd.num_samps = buff.size() + nsamps_to_discard; stream_cmd.stream_now = true; usrp->issue_stream_cmd(stream_cmd); size_t num_rx_samps = 0; // Discard the transient samples. rx_stream->recv(&discard_buff.front(), discard_buff.size(), md); if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { throw std::runtime_error(str(boost::format( "Receiver error: %s" ) % md.strerror())); } // Now capture the data we want num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md); //validate the received data if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { throw std::runtime_error(str(boost::format( "Receiver error: %s" ) % md.strerror())); } //we can live if all the data didnt come in if (num_rx_samps > buff.size()/2) { buff.resize(num_rx_samps); return; } if (num_rx_samps != buff.size()) throw std::runtime_error("did not get all the samples requested"); }
double uhd_device::set_rates(double rate) { double actual_rt, actual_clk_rt; #if !defined(MULTICHAN) & !defined(RESAMPLE) // Make sure we can set the master clock rate on this device actual_clk_rt = usrp_dev->get_master_clock_rate(); if (actual_clk_rt > U1_DEFAULT_CLK_RT) { LOG(ALERT) << "Cannot set clock rate on this device"; LOG(ALERT) << "Please compile with host resampling support"; return -1.0; } // Set master clock rate usrp_dev->set_master_clock_rate(master_clk_rt); actual_clk_rt = usrp_dev->get_master_clock_rate(); if (actual_clk_rt != master_clk_rt) { LOG(ALERT) << "Failed to set master clock rate"; LOG(ALERT) << "Actual clock rate " << actual_clk_rt; return -1.0; } #endif // Set sample rates usrp_dev->set_tx_rate(rate); usrp_dev->set_rx_rate(rate); actual_rt = usrp_dev->get_tx_rate(); if (actual_rt != rate) { LOG(ALERT) << "Actual sample rate differs from desired rate"; LOG(ALERT) << actual_rt << "Hz"; return -1.0; } if (usrp_dev->get_rx_rate() != actual_rt) { LOG(ALERT) << "Transmit and receive sample rates do not match"; return -1.0; } return actual_rt; }
/*********************************************************************** * Function to find optimal RX gain setting (for the current frequency) **********************************************************************/ UHD_INLINE void set_optimal_rx_gain( uhd::usrp::multi_usrp::sptr usrp, uhd::rx_streamer::sptr rx_stream, double wave_freq = 0.0) { const double gain_step = 3.0; const double gain_compression_threshold = gain_step * 0.5; const double actual_rx_rate = usrp->get_rx_rate(); const double actual_tx_freq = usrp->get_tx_freq(); const double actual_rx_freq = usrp->get_rx_freq(); const double bb_tone_freq = actual_tx_freq - actual_rx_freq + wave_freq; const size_t nsamps = size_t(actual_rx_rate / default_fft_bin_size); std::vector<samp_type> buff(nsamps); uhd::gain_range_t rx_gain_range = usrp->get_rx_gain_range(); double rx_gain = rx_gain_range.start() + gain_step; double curr_dbrms = 0.0; double prev_dbrms = 0.0; double delta = 0.0; // No sense in setting the gain where this is no gain range if (rx_gain_range.stop() - rx_gain_range.start() < gain_step) return; // The algorithm below cycles through the RX gain range // looking for the point where the signal begins to get // clipped and the gain begins to be compressed. It does // this by looking for the gain setting where the increase // in the tone is less than the gain step by more than the // gain compression threshold (curr - prev < gain - threshold). // Initialize prev_dbrms value usrp->set_rx_gain(rx_gain); capture_samples(usrp, rx_stream, buff, nsamps); prev_dbrms = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate); rx_gain += gain_step; // Find RX gain where signal begins to clip while (rx_gain <= rx_gain_range.stop()) { usrp->set_rx_gain(rx_gain); capture_samples(usrp, rx_stream, buff, nsamps); curr_dbrms = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate); delta = curr_dbrms - prev_dbrms; // check if the gain is compressed beyone the threshold if (delta < gain_step - gain_compression_threshold) break; // if so, we are done prev_dbrms = curr_dbrms; rx_gain += gain_step; } // The rx_gain value at this point is the gain setting where clipping // occurs or the gain setting that is just beyond the gain range. // The gain is reduced by 2 steps to make sure it is within the range and // under the point where it is clipped with enough room to make adjustments. rx_gain -= 2 * gain_step; // Make sure the gain is within the range. rx_gain = rx_gain_range.clip(rx_gain); // Finally, set the gain. usrp->set_rx_gain(rx_gain); }
/*********************************************************************** * recv_to_file function **********************************************************************/ template<typename samp_type> void recv_to_file( uhd::usrp::multi_usrp::sptr usrp, const std::string &cpu_format, const std::string &wire_format, const std::string &file, size_t samps_per_buff, int num_requested_samples, double settling_time, std::vector<size_t> rx_channel_nums ){ int num_total_samps = 0; //create a receive streamer uhd::stream_args_t stream_args(cpu_format,wire_format); stream_args.channels = rx_channel_nums; uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); // Prepare buffers for received samples and metadata uhd::rx_metadata_t md; std::vector <std::vector< samp_type > > buffs( rx_channel_nums.size(), std::vector< samp_type >(samps_per_buff) ); //create a vector of pointers to point to each of the channel buffers std::vector<samp_type *> buff_ptrs; for (size_t i = 0; i < buffs.size(); i++) { buff_ptrs.push_back(&buffs[i].front()); } // Create one ofstream object per channel // (use shared_ptr because ofstream is non-copyable) std::vector<boost::shared_ptr<std::ofstream> > outfiles; for (size_t i = 0; i < buffs.size(); i++) { const std::string this_filename = generate_out_filename(file, buffs.size(), i); outfiles.push_back(boost::shared_ptr<std::ofstream>(new std::ofstream(this_filename.c_str(), std::ofstream::binary))); } UHD_ASSERT_THROW(outfiles.size() == buffs.size()); UHD_ASSERT_THROW(buffs.size() == rx_channel_nums.size()); bool overflow_message = true; double timeout = settling_time + 0.1f; //expected settling time + padding for first recv //setup streaming uhd::stream_cmd_t stream_cmd((num_requested_samples == 0)? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS: uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE ); stream_cmd.num_samps = num_requested_samples; stream_cmd.stream_now = false; stream_cmd.time_spec = uhd::time_spec_t(settling_time); rx_stream->issue_stream_cmd(stream_cmd); while(not stop_signal_called and (num_requested_samples > num_total_samps or num_requested_samples == 0)){ size_t num_rx_samps = rx_stream->recv(buff_ptrs, samps_per_buff, md, timeout); timeout = 0.1f; //small timeout for subsequent recv if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) { std::cout << boost::format("Timeout while streaming") << std::endl; break; } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW){ if (overflow_message){ overflow_message = false; std::cerr << boost::format( "Got an overflow indication. Please consider the following:\n" " Your write medium must sustain a rate of %fMB/s.\n" " Dropped samples will not be written to the file.\n" " Please modify this example for your purposes.\n" " This message will not appear again.\n" ) % (usrp->get_rx_rate()*sizeof(samp_type)/1e6); } continue; } if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ throw std::runtime_error(str(boost::format( "Receiver error %s" ) % md.strerror())); } num_total_samps += num_rx_samps; for (size_t i = 0; i < outfiles.size(); i++) { outfiles[i]->write((const char*) buff_ptrs[i], num_rx_samps*sizeof(samp_type)); } } // Shut down receiver stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; rx_stream->issue_stream_cmd(stream_cmd); // Close files for (size_t i = 0; i < outfiles.size(); i++) { outfiles[i]->close(); } }
template<typename samp_type> void recv_to_file( uhd::usrp::multi_usrp::sptr usrp, const std::string &cpu_format, const std::string &wire_format, const std::string &file, size_t samps_per_buff, unsigned long long num_requested_samples, double time_requested = 0.0, bool bw_summary = false, bool stats = false, bool null = false, bool enable_size_map = false, bool continue_on_bad_packet = false ){ unsigned long long num_total_samps = 0; //create a receive streamer uhd::stream_args_t stream_args(cpu_format,wire_format); uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); uhd::rx_metadata_t md; std::vector<samp_type> buff(samps_per_buff); std::ofstream outfile; if (not null) outfile.open(file.c_str(), std::ofstream::binary); bool overflow_message = true; //setup streaming uhd::stream_cmd_t stream_cmd((num_requested_samples == 0)? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS: uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE ); stream_cmd.num_samps = num_requested_samples; stream_cmd.stream_now = true; stream_cmd.time_spec = uhd::time_spec_t(); rx_stream->issue_stream_cmd(stream_cmd); boost::system_time start = boost::get_system_time(); unsigned long long ticks_requested = (long)(time_requested * (double)boost::posix_time::time_duration::ticks_per_second()); boost::posix_time::time_duration ticks_diff; boost::system_time last_update = start; unsigned long long last_update_samps = 0; typedef std::map<size_t,size_t> SizeMap; SizeMap mapSizes; while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)) { boost::system_time now = boost::get_system_time(); size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, 3.0, enable_size_map); if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) { std::cout << boost::format("Timeout while streaming") << std::endl; break; } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW){ if (overflow_message) { overflow_message = false; std::cerr << boost::format( "Got an overflow indication. Please consider the following:\n" " Your write medium must sustain a rate of %fMB/s.\n" " Dropped samples will not be written to the file.\n" " Please modify this example for your purposes.\n" " This message will not appear again.\n" ) % (usrp->get_rx_rate()*sizeof(samp_type)/1e6); } continue; } if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ std::string error = str(boost::format("Receiver error: %s") % md.strerror()); if (continue_on_bad_packet){ std::cerr << error << std::endl; continue; } else throw std::runtime_error(error); } if (enable_size_map) { SizeMap::iterator it = mapSizes.find(num_rx_samps); if (it == mapSizes.end()) mapSizes[num_rx_samps] = 0; mapSizes[num_rx_samps] += 1; } num_total_samps += num_rx_samps; if (outfile.is_open()) outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type)); if (bw_summary) { last_update_samps += num_rx_samps; boost::posix_time::time_duration update_diff = now - last_update; if (update_diff.ticks() > boost::posix_time::time_duration::ticks_per_second()) { double t = (double)update_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); double r = (double)last_update_samps / t; std::cout << boost::format("\t%f Msps") % (r/1e6) << std::endl; last_update_samps = 0; last_update = now; } } ticks_diff = now - start; if (ticks_requested > 0){ if ((unsigned long long)ticks_diff.ticks() > ticks_requested) break; } } stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; rx_stream->issue_stream_cmd(stream_cmd); if (outfile.is_open()) outfile.close(); if (stats) { std::cout << std::endl; double t = (double)ticks_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second(); std::cout << boost::format("Received %d samples in %f seconds") % num_total_samps % t << std::endl; double r = (double)num_total_samps / t; std::cout << boost::format("%f Msps") % (r/1e6) << std::endl; if (enable_size_map) { std::cout << std::endl; std::cout << "Packet size map (bytes: count)" << std::endl; for (SizeMap::iterator it = mapSizes.begin(); it != mapSizes.end(); it++) std::cout << it->first << ":\t" << it->second << std::endl; } } }
int setupUSRP( uhd::usrp::multi_usrp::sptr& usrp, const float center_freq, const float sample_rate, const int rx_gain, const char* dev_addr) { //Initialize the USRP to the specified address usrp = uhd::usrp::multi_usrp::make(string(dev_addr)); //Define the clock reference usrp->set_clock_source(__USRP_CLK_SRC); //Output some useful information cout << "Using the following USRP device: " << endl << usrp->get_pp_string() << endl; //Try setting the sample rate. If the rate we get is not the same as the //requested rate, we will return with a warning to ensure the user is aware //of the actual sample rate usrp->set_rx_rate( sample_rate ); if( usrp->get_rx_rate() != sample_rate ) { ios_base::fmtflags originalFlags = cout.flags(); cout.setf(ios_base::left,ios_base::floatfield); cout.precision(15); cout << "WARNING! Requested rate = " << sample_rate << endl << "WARNING! Actual rate = " << usrp->get_rx_rate() << endl; cout.setf(originalFlags); } //Try setting the center frequency. Like above, if we get a different //frequency than the one we're requesting, we will spit out a warning for the //user usrp->set_rx_freq( center_freq ); if( usrp->get_rx_freq() != center_freq ) { ios_base::fmtflags originalFlags = cout.flags(); cout.setf(ios_base::left,ios_base::floatfield); cout.precision(15); cout << "WARNING! Requested frequency = " << center_freq << endl << "WARNING! Actual frequency = " << usrp->get_rx_freq() << endl; cout.setf(originalFlags); } //Set the RX gain. There really shouldn't be any problems here, but the user //might request something silly like 50dB of gain when the module can't //accomodate. So we'll perform a similar check here. usrp->set_rx_gain( rx_gain ); if( usrp->get_rx_gain() != rx_gain ) { cout << "WARNING! Requested gain = " << rx_gain << endl << "WARNING! Actual gain = " << usrp->get_rx_gain() << endl; } //Ensure the LO locked vector<string> sensor_names; sensor_names = usrp->get_rx_sensor_names(0); if( find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end() ) { uhd::sensor_value_t lo_locked = usrp->get_rx_sensor("lo_locked",0); cout << "Checking RX: " << endl << lo_locked.to_pp_string() << endl; UHD_ASSERT_THROW(lo_locked.to_bool()); //We should probably catch this } return 1; }
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(); }
/*********************************************************************** * recv_to_file function **********************************************************************/ template<typename samp_type> void recv_to_file( uhd::usrp::multi_usrp::sptr usrp, const std::string &cpu_format, const std::string &wire_format, const std::string &file, size_t samps_per_buff, int num_requested_samples, float settling_time, std::vector<size_t> rx_channel_nums ) { int num_total_samps = 0; //create a receive streamer uhd::stream_args_t stream_args(cpu_format,wire_format); stream_args.channels = rx_channel_nums; uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); uhd::rx_metadata_t md; std::vector<samp_type> buff(samps_per_buff); std::ofstream outfile(file.c_str(), std::ofstream::binary); bool overflow_message = true; float timeout = settling_time + 0.1; //expected settling time + padding for first recv //setup streaming uhd::stream_cmd_t stream_cmd((num_requested_samples == 0)? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS: uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE ); stream_cmd.num_samps = num_requested_samples; stream_cmd.stream_now = false; stream_cmd.time_spec = uhd::time_spec_t(settling_time); rx_stream->issue_stream_cmd(stream_cmd); while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)) { size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, timeout); timeout = 0.1; //small timeout for subsequent recv if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) { std::cout << boost::format("Timeout while streaming") << std::endl; break; } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) { if (overflow_message) { overflow_message = false; std::cerr << boost::format( "Got an overflow indication. Please consider the following:\n" " Your write medium must sustain a rate of %fMB/s.\n" " Dropped samples will not be written to the file.\n" " Please modify this example for your purposes.\n" " This message will not appear again.\n" ) % (usrp->get_rx_rate()*sizeof(samp_type)/1e6); } continue; } if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { throw std::runtime_error(str(boost::format( "Receiver error %s" ) % md.strerror())); } num_total_samps += num_rx_samps; outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type)); } outfile.close(); }
/*********************************************************************** * Benchmark RX Rate **********************************************************************/ void benchmark_rx_rate( uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, uhd::rx_streamer::sptr rx_stream, bool random_nsamps, const boost::posix_time::ptime &start_time, std::atomic<bool>& burst_timer_elapsed ) { uhd::set_thread_priority_safe(); //print pre-test summary std::cout << boost::format( "[%s] Testing receive rate %f Msps on %u channels" ) % NOW() % (usrp->get_rx_rate()/1e6) % rx_stream->get_num_channels() << std::endl; //setup variables and allocate buffer uhd::rx_metadata_t md; const size_t max_samps_per_packet = rx_stream->get_max_num_samps(); std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(rx_cpu)); std::vector<void *> buffs; for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++) buffs.push_back(&buff.front()); //same buffer for each channel bool had_an_overflow = false; uhd::time_spec_t last_time; const double rate = usrp->get_rx_rate(); uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(INIT_DELAY); cmd.stream_now = (buffs.size() == 1); rx_stream->issue_stream_cmd(cmd); const float burst_pkt_time = std::max<float>(0.100f, (2 * max_samps_per_packet/rate)); float recv_timeout = burst_pkt_time + INIT_DELAY; bool stop_called = false; while (true) { //if (burst_timer_elapsed.load(boost::memory_order_relaxed) and not stop_called) { if (burst_timer_elapsed and not stop_called) { rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); stop_called = true; } if (random_nsamps) { cmd.num_samps = rand() % max_samps_per_packet; rx_stream->issue_stream_cmd(cmd); } try { num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md, recv_timeout)*rx_stream->get_num_channels(); recv_timeout = burst_pkt_time; } catch (uhd::io_error &e) { std::cerr << "[" << NOW() << "] Caught an IO exception. " << std::endl; std::cerr << e.what() << std::endl; return; } //handle the error codes switch(md.error_code){ case uhd::rx_metadata_t::ERROR_CODE_NONE: if (had_an_overflow) { had_an_overflow = false; const long dropped_samps = (md.time_spec - last_time).to_ticks(rate); if (dropped_samps < 0) { std::cerr << "[" << NOW() << "] Timestamp after overrun recovery " "ahead of error timestamp! Unable to calculate " "number of dropped samples." "(Delta: " << dropped_samps << " ticks)\n"; } num_dropped_samps += std::max<long>(1, dropped_samps); } if ((burst_timer_elapsed or stop_called) and md.end_of_burst) { return; } break; // ERROR_CODE_OVERFLOW can indicate overflow or sequence error case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: last_time = md.time_spec; had_an_overflow = true; // check out_of_sequence flag to see if it was a sequence error or overflow if (!md.out_of_sequence) { num_overruns++; } else { num_seqrx_errors++; std::cerr << "[" << NOW() << "] Detected Rx sequence error." << std::endl; } break; case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND: std::cerr << "[" << NOW() << "] Receiver error: " << md.strerror() << ", restart streaming..."<< std::endl; num_late_commands++; // Radio core will be in the idle state. Issue stream command to restart streaming. cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(0.05); cmd.stream_now = (buffs.size() == 1); rx_stream->issue_stream_cmd(cmd); break; case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: if (burst_timer_elapsed) { return; } std::cerr << "[" << NOW() << "] Receiver error: " << md.strerror() << ", continuing..." << std::endl; num_timeouts_rx++; break; // Otherwise, it's an error default: std::cerr << "[" << NOW() << "] Receiver error: " << md.strerror() << std::endl; std::cerr << "[" << NOW() << "] Unexpected error on recv, continuing..." << std::endl; break; } } }