/*********************************************************************** * Transmit thread **********************************************************************/ static void tx_thread(uhd::usrp::multi_usrp::sptr usrp, const double tx_wave_ampl) { uhd::set_thread_priority_safe(); //create a transmit streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); //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); //fill buff and send until interrupted while (not boost::this_thread::interruption_requested()) { for (size_t i = 0; i < buff.size(); i++) buff[i] = float(tx_wave_ampl); tx_stream->send(&buff.front(), buff.size(), md); } //send a mini EOB packet md.end_of_burst = true; tx_stream->send("", 0, md); }
/*********************************************************************** * Transmit thread **********************************************************************/ static void tx_thread(uhd::usrp::multi_usrp::sptr usrp, 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()); //create a transmit streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); //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); }
template<class T, class... U> void stream_args(std::ostream & out, const char * names, const T & first, const U &... rest) { while(*names && *names != ',') out << *names++; out << ':' << first << ", "; while(*names && (*names == ',' || isspace(*names))) ++names; stream_args(out, names, rest...); }
cvec BlindOFDM_UHDDevice::readsamples(int Nsamples,double timestamp) { //uhd::rx_metadata_t rx_md; uhd::stream_args_t stream_args("fc64"); uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); cvec rx_buff; cvec rx_buff2; int num_rx_samps=0; int lost_samples=500; //Receiving mode uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); //allocate buffer with data to receive rx_buff.set_size(lost_samples+Nsamples); rx_buff.zeros(); rx_buff2.set_size(Nsamples); rx_buff2.zeros(); stream_cmd.num_samps = rx_buff.size(); stream_cmd.stream_now = false; stream_cmd.time_spec = uhd::time_spec_t(timestamp-lost_samples/rx_rate); usrp->issue_stream_cmd(stream_cmd); num_rx_samps=rx_stream->recv(&rx_buff(0), rx_buff.size(), rx_md, timestamp-lost_samples/rx_rate,false); rx_buff2=rx_buff.get(lost_samples,lost_samples+Nsamples-1); //cout << "First receive time sample " <<((rx_md.time_spec).get_real_secs()+lost_samples/rx_rate)*1.0e9 << " nanoseconds" << endl; //if(num_rx_samps==lost_samples+Nsamples) // cout << "Number of samples acquired by the Rx streamer " << rx_buff2.size() << endl; //else // cout << "Error in the number of samples acquired by the Rx streamer " << endl; return rx_buff2; }
template<typename samp_type> void send_from_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 ){ //create a transmit streamer uhd::stream_args_t stream_args(cpu_format, wire_format); uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); uhd::tx_metadata_t md; md.start_of_burst = false; md.end_of_burst = false; std::vector<samp_type> buff(samps_per_buff); std::ifstream infile(file.c_str(), std::ifstream::binary); //loop until the entire file has been read while(not md.end_of_burst and not stop_signal_called){ infile.read((char*)&buff.front(), buff.size()*sizeof(samp_type)); size_t num_tx_samps = infile.gcount()/sizeof(samp_type); md.end_of_burst = infile.eof(); tx_stream->send(&buff.front(), num_tx_samps, md); } infile.close(); }
/*********************************************************************** * 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; } } }
uhd::rx_streamer::sptr Responder::create_rx_streamer(uhd::usrp::multi_usrp::sptr usrp) { uhd::stream_args_t stream_args("fc32"); //complex floats if (_samps_per_packet > 0) { stream_args.args["spp"] = str(boost::format("%d") % _samps_per_packet); } uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); _samps_per_packet = rx_stream->get_max_num_samps(); return rx_stream; }
bool UHDDevice::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 false; } /* 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 false; } /* Check for a valid device type and set bus type */ if (!parse_dev_type()) return false; if (extref) usrp_dev->set_clock_source("external"); /* 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(tx_rate, rx_rate); /* Create receive buffer */ size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t); rx_buffer = new SampleBuffer(buf_len, rx_rate); /* Set receive chain sample offset */ ts_offset = get_dev_offset(dev_type); /* Initialize and shadow gain values */ init_gains(); LOG(INFO) << "\n" << usrp_dev->get_pp_string(); return true; }
uhd_streamer::uhd_streamer (uhdInput *d) { m_theStick = d; m_stop_signal_called = false; //create a receive streamer uhd::stream_args_t stream_args( "fc32", "sc16" ); m_theStick -> m_rx_stream = m_theStick -> m_usrp -> get_rx_stream (stream_args); //setup streaming uhd::stream_cmd_t stream_cmd (uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS ); stream_cmd.num_samps = 0; stream_cmd.stream_now = true; stream_cmd.time_spec = uhd::time_spec_t(); m_theStick -> m_rx_stream -> issue_stream_cmd (stream_cmd); start(); }
int cuhd_open(char *args, void **h) { cuhd_handler* handler = new cuhd_handler(); std::string _args=std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args); handler->usrp->set_clock_source("internal"); std::string otw, cpu; otw="sc16"; cpu="fc32"; uhd::stream_args_t stream_args(cpu, otw); handler->rx_stream = handler->usrp->get_rx_stream(stream_args); handler->tx_stream = handler->usrp->get_tx_stream(stream_args); *h = handler; return 0; }
int cuhd_open_(char *args, void **h, bool create_thread_gain, bool tx_gain_same_rx) { uhd::set_thread_priority_safe(); cuhd_handler *handler = new cuhd_handler(); std::string _args = std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args); handler->usrp->set_clock_source("internal"); std::string otw, cpu; otw = "sc16"; cpu = "fc32"; uhd::stream_args_t stream_args(cpu, otw); handler->rx_stream = handler->usrp->get_rx_stream(stream_args); handler->tx_stream = handler->usrp->get_tx_stream(stream_args); handler->rx_nof_samples = handler->rx_stream->get_max_num_samps(); handler->tx_nof_samples = handler->tx_stream->get_max_num_samps(); handler->tx_gain_same_rx = tx_gain_same_rx; handler->tx_rx_gain_offset = 0.0; handler->rx_gain_range = handler->usrp->get_rx_gain_range(); handler->tx_gain_range = handler->usrp->get_tx_gain_range(); *h = handler; if (create_thread_gain) { if (pthread_mutex_init(&handler->mutex, NULL)) { return -1; } if (pthread_cond_init(&handler->cond, NULL)) { return -1; } if (pthread_create(&handler->thread_gain, NULL, thread_gain_fcn, *h)) { perror("pthread_create"); return -1; } } return 0; }
BlindOFDM_UHDDevice::BlindOFDM_UHDDevice() { //Create the USRP string args=""; usrp = uhd::usrp::multi_usrp::make(args); timeout=1.0; tx_rate=2.0e6; tx_freq=433.92e6; tx_gain=usrp->get_tx_gain_range().stop()/2; tx_amplitude=0.1; rx_rate=2.0e6; rx_freq=433.92e6; rx_gain=0; uhd::stream_args_t stream_args("fc64"); //complex doubles //create a transmit streamer tx_stream = usrp->get_tx_stream(stream_args); //create a receive streamer rx_stream = usrp->get_rx_stream(stream_args); usrp->set_time_now(uhd::time_spec_t(0.0)); cout << "Setting device timestamp to 0" << endl; is_sending=false; is_receiving=false; timestamp=0; tx_timestamp=0; time_gap=0; correction=0; previous_correction=0; has_sent=false; tx_buff.set_size(1); tx_buff.zeros(); rx_buff_size=0; rx_buff.set_size(1); rx_buff.zeros(); sync_time=0; sync_time2=0; }
/*********************************************************************** * TX Hammer **********************************************************************/ void tx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_cpu, const std::string &tx_otw){ uhd::set_thread_priority_safe(); //create a transmit streamer uhd::stream_args_t stream_args(tx_cpu, tx_otw); for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping stream_args.channels.push_back(ch); uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); uhd::tx_metadata_t md; std::vector<std::complex<float> > buff(10000); //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(&buff, tx_stream->get_max_num_samps(), 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); } }
int uhd_open(char *args, void **h) { uhd_handler* handler = new uhd_handler(); std::string _args=std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args); //uhd::msg::register_handler(&my_handler); std::string otw, cpu; otw="sc16"; cpu="fc32"; handler->usrp->set_clock_source("internal"); uhd::stream_args_t stream_args(cpu, otw); // stream_args.channels.push_back(0); // stream_args.args["noclear"] = "1"; handler->rx_stream = handler->usrp->get_rx_stream(stream_args); *h = handler; int size = 10000*handler->rx_stream->get_max_num_samps(); return 0; }
int cuhd_open(char *args, void **h) { cuhd_handler *handler = new cuhd_handler(); std::string _args = std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000" + ", num_recv_frames=512"); // handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512"); handler->usrp->set_clock_source("internal"); #ifdef HIDE_MESSAGES uhd::msg::register_handler(my_handler); #endif std::string otw, cpu; otw = "sc16"; cpu = "fc32"; uhd::stream_args_t stream_args(cpu, otw); handler->rx_stream = handler->usrp->get_rx_stream(stream_args); handler->tx_stream = handler->usrp->get_tx_stream(stream_args); *h = handler; return 0; }
int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //variables to be set by po std::string args; double seconds_in_future; size_t total_num_samps; double rate; float ampl; double freq; double rep_rate; double gain; //setup the program options 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") ("secs", po::value<double>(&seconds_in_future)->default_value(1.5), "delay before first burst") ("repeat", "repeat burst") ("rep-delay", po::value<double>(&rep_rate)->default_value(0.5), "delay between bursts") ("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000), "total number of samples to transmit") ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of outgoing samples") ("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of each sample") ("freq", po::value<double>(&freq)->default_value(0), "center frequency") ("gain", po::value<double>(&gain)->default_value(0), "gain") ("dilv", "specify to disable inner-loop verbose") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl; return ~0; } bool verbose = vm.count("dilv") == 0; bool repeat = vm.count("repeat") != 0; //create a usrp device std::cout << std::endl; 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); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; //set the tx sample rate std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; usrp->set_tx_rate(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; for(size_t i=0; i < usrp->get_tx_num_channels(); i++) usrp->set_tx_freq(freq, i); std::cout << boost::format("Actual TX Freq: %f MHz...") % (usrp->get_tx_freq()/1e6) << std::endl << std::endl; std::cout << boost::format("Setting TX Gain: %f...") % (gain) << std::endl; for(size_t i=0; i < usrp->get_tx_num_channels(); i++) usrp->set_tx_gain(gain, i); std::cout << boost::format("Actual TX Gain: %f...") % (usrp->get_tx_gain()) << std::endl << std::endl; std::cout << boost::format("Setting device timestamp to 0...") << std::endl; usrp->set_time_now(uhd::time_spec_t(0.0)); //create a transmit streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); //allocate buffer with data to send const size_t spb = tx_stream->get_max_num_samps(); std::vector<std::complex<float> *> buffs; for(size_t i=0; i < usrp->get_num_mboards(); i++) { buffs.push_back(new std::complex<float>[spb]); for(size_t n=0; n < spb; n++) buffs.back()[n] = std::complex<float>(ampl, ampl); }; std::signal(SIGINT, &sig_int_handler); if(repeat) std::cout << "Press Ctrl + C to quit..." << std::endl; double time_to_send = seconds_in_future; do { //setup metadata for the first packet 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(time_to_send); //the first call to send() will block this many seconds before sending: double timeout = std::max(rep_rate, seconds_in_future) + 0.1; //timeout (delay before transmit + padding) size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ size_t samps_to_send = std::min(total_num_samps - num_acc_samps, spb); //ensure the the last packet has EOB set md.end_of_burst = samps_to_send < spb; //send a single packet size_t num_tx_samps = tx_stream->send( buffs, samps_to_send, md, timeout ); //do not use time spec for subsequent packets md.has_time_spec = false; md.start_of_burst = false; if (num_tx_samps < samps_to_send) std::cerr << "Send timeout..." << std::endl; if(verbose) std::cout << boost::format("Sent packet: %u samples") % num_tx_samps << std::endl; num_acc_samps += num_tx_samps; } time_to_send += rep_rate; std::cout << std::endl << "Waiting for async burst ACK... " << std::flush; uhd::async_metadata_t async_md; bool got_async_burst_ack = false; //loop through all messages for the ACK packet (may have underflow messages in queue) while (not got_async_burst_ack and usrp->get_device()->recv_async_msg(async_md, seconds_in_future)){ got_async_burst_ack = (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK); } std::cout << (got_async_burst_ack? "success" : "fail") << std::endl; } while (not stop_signal_called and repeat); //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return 0; }
int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //variables to be set by po std::string args, sync, subdev; double seconds_in_future; size_t total_num_samps; double rate; //setup the program options po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args") ("secs", po::value<double>(&seconds_in_future)->default_value(1.5), "number of seconds in the future to receive") ("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000), "total number of samples to receive") ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples") ("sync", po::value<std::string>(&sync)->default_value("now"), "synchronization method: now, pps, mimo") ("subdev", po::value<std::string>(&subdev), "subdev spec (homogeneous across motherboards)") ("dilv", "specify to disable inner-loop verbose") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("UHD RX Multi Samples %s") % desc << std::endl; std::cout << " This is a demonstration of how to receive aligned data from multiple channels.\n" " This example can receive from multiple DSPs, multiple motherboards, or both.\n" " The MIMO cable or PPS can be used to synchronize the configuration. See --sync\n" "\n" " Specify --subdev to select multiple channels per motherboard.\n" " Ex: --subdev=\"0:A 0:B\" to get 2 channels on a Basic RX.\n" "\n" " Specify --args to select multiple motherboards in a configuration.\n" " Ex: --args=\"addr0=192.168.10.2, addr1=192.168.10.3\"\n" << std::endl; return ~0; } bool verbose = vm.count("dilv") == 0; //create a usrp device std::cout << std::endl; 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); //always select the subdevice first, the channel mapping affects the other settings if (vm.count("subdev")) usrp->set_rx_subdev_spec(subdev); //sets across all mboards std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; //set the rx sample rate (sets across all channels) 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; std::cout << boost::format("Setting device timestamp to 0...") << std::endl; if (sync == "now"){ //This is not a true time lock, the devices will be off by a few RTT. //Rather, this is just to allow for demonstration of the code below. usrp->set_time_now(uhd::time_spec_t(0.0)); } else if (sync == "pps"){ usrp->set_time_source("external"); usrp->set_time_unknown_pps(uhd::time_spec_t(0.0)); boost::this_thread::sleep(boost::posix_time::seconds(1)); //wait for pps sync pulse } else if (sync == "mimo"){ UHD_ASSERT_THROW(usrp->get_num_mboards() == 2); //make mboard 1 a slave over the MIMO Cable usrp->set_clock_source("mimo", 1); usrp->set_time_source("mimo", 1); //set time on the master (mboard 0) usrp->set_time_now(uhd::time_spec_t(0.0), 0); //sleep a bit while the slave locks its time to the master boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } //create a receive streamer //linearly map channels (index0 = channel0, index1 = channel1, ...) uhd::stream_args_t stream_args("fc32"); //complex floats for (size_t chan = 0; chan < usrp->get_rx_num_channels(); chan++) stream_args.channels.push_back(chan); //linear mapping uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //setup streaming std::cout << std::endl; std::cout << boost::format( "Begin streaming %u samples, %f seconds in the future..." ) % total_num_samps % seconds_in_future << std::endl; uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); stream_cmd.num_samps = total_num_samps; stream_cmd.stream_now = false; stream_cmd.time_spec = uhd::time_spec_t(seconds_in_future); usrp->issue_stream_cmd(stream_cmd); //tells all channels to stream //meta-data will be filled in by recv() uhd::rx_metadata_t md; //allocate buffers to receive with samples (one buffer per channel) const size_t samps_per_buff = rx_stream->get_max_num_samps(); std::vector<std::vector<std::complex<float> > > buffs( usrp->get_rx_num_channels(), std::vector<std::complex<float> >(samps_per_buff) ); //create a vector of pointers to point to each of the channel buffers std::vector<std::complex<float> *> buff_ptrs; for (size_t i = 0; i < buffs.size(); i++) buff_ptrs.push_back(&buffs[i].front()); //the first call to recv() will block this many seconds before receiving double timeout = seconds_in_future + 0.1; //timeout (delay before receive + padding) size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ //receive a single packet size_t num_rx_samps = rx_stream->recv( buff_ptrs, samps_per_buff, md, timeout ); //use a small timeout for subsequent packets timeout = 0.1; //handle the error code if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break; if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ throw std::runtime_error(str(boost::format( "Unexpected error code 0x%x" ) % md.error_code)); } if(verbose) std::cout << boost::format( "Received packet: %u samples, %u full secs, %f frac secs" ) % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl; num_acc_samps += num_rx_samps; } if (num_acc_samps < total_num_samps) std::cerr << "Receive timeout before all samples received..." << std::endl; //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return 0; }
int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //variables to be set by po std::string args; //setup the program options po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("UHD Test Timed Commands %s") % desc << std::endl; return ~0; } //create a usrp device std::cout << std::endl; 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); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; //check if timed commands are supported std::cout << std::endl; std::cout << "Testing support for timed commands on this hardware... " << std::flush; try{ usrp->set_command_time(uhd::time_spec_t(0.0)); usrp->clear_command_time(); } catch (const std::exception &e){ std::cout << "fail" << std::endl; std::cerr << "Got exception: " << e.what() << std::endl; std::cerr << "Timed commands are not supported on this hardware." << std::endl; return ~0; } std::cout << "pass" << std::endl; //readback time really fast, time diff is small std::cout << std::endl; std::cout << "Perform fast readback of registers:" << std::endl; uhd::time_spec_t total_time; for (size_t i = 0; i < 100; i++){ const uhd::time_spec_t t0 = usrp->get_time_now(); const uhd::time_spec_t t1 = usrp->get_time_now(); total_time += (t1-t0); } std::cout << boost::format( "Difference between paired reads: %f us" ) % (total_time.get_real_secs()/100*1e6) << std::endl; //use a timed command to start a stream at a specific time //this is not the right way start streaming at time x, //but it should approximate it within control RTT/2 //setup streaming std::cout << std::endl; std::cout << "About to start streaming using timed command:" << std::endl; //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); stream_cmd.num_samps = 100; stream_cmd.stream_now = true; const uhd::time_spec_t stream_time = usrp->get_time_now() + uhd::time_spec_t(0.1); usrp->set_command_time(stream_time); rx_stream->issue_stream_cmd(stream_cmd); usrp->clear_command_time(); //meta-data will be filled in by recv() uhd::rx_metadata_t md; //allocate buffer to receive with samples std::vector<std::complex<float> > buff(stream_cmd.num_samps); const size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, 1.0); if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ throw std::runtime_error(str(boost::format( "Unexpected error code 0x%x" ) % md.error_code)); } std::cout << boost::format( "Received packet: %u samples, %u full secs, %f frac secs" ) % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl; std::cout << boost::format( "Stream time was: %u full secs, %f frac secs" ) % stream_time.get_full_secs() % stream_time.get_frac_secs() << std::endl; std::cout << boost::format( "Difference between stream time and first packet: %f us" ) % ((md.time_spec-stream_time).get_real_secs()/100*1e6) << std::endl; //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return EXIT_SUCCESS; }
/*********************************************************************** * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]) { std::string args, subdev, serial; double tx_wave_freq, tx_wave_ampl, rx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; double precision; po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("verbose", "enable some verbose") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')") ("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz") ("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)") ("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)") ("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz") ("nsamps", po::value<size_t>(&nsamps), "Samples per data capture") ("precision", po::value<double>(&precision)->default_value(default_precision), "Correction precision (default=0.0001)") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")) { std::cout << boost::format("USRP Generate TX IQ Balance Calibration Table %s") % desc << std::endl; std::cout << "This application measures leakage between RX and TX on a transceiver daughterboard to self-calibrate.\n" "Note: Not all daughterboards support this feature. Refer to the UHD manual for details.\n" << std::endl; return EXIT_FAILURE; } // Create a USRP device uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, subdev, serial); if (not vm.count("nsamps")) nsamps = size_t(usrp->get_rx_rate() / default_fft_bin_size); //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //create a transmitter thread boost::thread_group threads; threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_freq, tx_wave_ampl)); //re-usable buffer for samples std::vector<samp_type> buff; //store the results here std::vector<result_t> results; if (not vm.count("freq_start")) freq_start = usrp->get_fe_tx_freq_range().start(); if (not vm.count("freq_stop")) freq_stop = usrp->get_fe_tx_freq_range().stop(); //check start and stop frequencies if (freq_start < usrp->get_fe_tx_freq_range().start()) { std::cerr << "freq_start must be " << usrp->get_fe_tx_freq_range().start() << " or greater for this daughter board" << std::endl; return EXIT_FAILURE; } if (freq_stop > usrp->get_fe_tx_freq_range().stop()) { std::cerr << "freq_stop must be " << usrp->get_fe_tx_freq_range().stop() << " or less for this daughter board" << std::endl; return EXIT_FAILURE; } //check rx_offset double min_rx_offset = usrp->get_rx_freq_range().start() - usrp->get_fe_tx_freq_range().start(); double max_rx_offset = usrp->get_rx_freq_range().stop() - usrp->get_fe_tx_freq_range().stop(); if (rx_offset < min_rx_offset or rx_offset > max_rx_offset) { std::cerr << "rx_offset must be between " << min_rx_offset << " and " << max_rx_offset << " for this daughter board" << std::endl; return EXIT_FAILURE; } UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl; for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step) { const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset); //frequency constants for this tune event 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 + tx_wave_freq - actual_rx_freq; const double bb_imag_freq = actual_tx_freq - tx_wave_freq - actual_rx_freq; //reset TX IQ balance usrp->set_tx_iq_balance(0.0); //set optimal RX gain setting for this frequency set_optimal_rx_gain(usrp, rx_stream, tx_wave_freq); //capture initial uncorrected value capture_samples(usrp, rx_stream, buff, nsamps); const double initial_suppression = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate) - compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate); //bounds and results from searching double phase_corr_start = -1.0; double phase_corr_stop = 1.0; double phase_corr_step = (phase_corr_stop - phase_corr_start)/(num_search_steps+1); double ampl_corr_start = -1.0; double ampl_corr_stop = 1.0; double ampl_corr_step = (ampl_corr_stop - ampl_corr_start)/(num_search_steps+1); double best_suppression = 0; double best_phase_corr = 0; double best_ampl_corr = 0; while (phase_corr_step >= precision or ampl_corr_step >= precision) { for (double phase_corr = phase_corr_start + phase_corr_step; phase_corr <= phase_corr_stop - phase_corr_step; phase_corr += phase_corr_step) { for (double ampl_corr = ampl_corr_start + ampl_corr_step; ampl_corr <= ampl_corr_stop - ampl_corr_step; ampl_corr += ampl_corr_step) { const std::complex<double> correction(ampl_corr, phase_corr); usrp->set_tx_iq_balance(correction); //receive some samples capture_samples(usrp, rx_stream, buff, nsamps); const double tone_dbrms = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate); const double imag_dbrms = compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate); const double suppression = tone_dbrms - imag_dbrms; if (suppression > best_suppression) { best_suppression = suppression; best_phase_corr = phase_corr; best_ampl_corr = ampl_corr; } } } phase_corr_start = best_phase_corr - phase_corr_step; phase_corr_stop = best_phase_corr + phase_corr_step; phase_corr_step = (phase_corr_stop - phase_corr_start)/(num_search_steps+1); ampl_corr_start = best_ampl_corr - ampl_corr_step; ampl_corr_stop = best_ampl_corr + ampl_corr_step; ampl_corr_step = (ampl_corr_stop - ampl_corr_start)/(num_search_steps+1); } if (best_suppression > initial_suppression) //keep result { result_t result; result.freq = tx_lo; result.real_corr = best_ampl_corr; result.imag_corr = best_phase_corr; result.best = best_suppression; result.delta = best_suppression - initial_suppression; results.push_back(result); if (vm.count("verbose")) std::cout << boost::format("TX IQ: %f MHz: best suppression %f dB, corrected %f dB") % (tx_lo/1e6) % result.best % result.delta << std::endl; else std::cout << "." << std::flush; } } std::cout << std::endl; //stop the transmitter threads.interrupt_all(); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); //wait for threads to finish threads.join_all(); store_results(results, "TX", "tx", "iq", serial); return EXIT_SUCCESS; }
int SHD_SAFE_MAIN(int argc, char *argv[]) { shd::set_thread_priority_safe(); //variables to be set by po std::string args; size_t ntests; //setup the program options po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "multi shd device address args") ("ntests", po::value<size_t>(&ntests)->default_value(50), "number of tests to run") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")) { std::cout << boost::format("SHD Test Messages %s") % desc << std::endl; return ~0; } //create a smini device std::cout << std::endl; std::cout << boost::format("Creating the smini device with: %s...") % args << std::endl; shd::smini::multi_smini::sptr smini = shd::smini::multi_smini::make(args); std::cout << boost::format("Using Device: %s") % smini->get_pp_string() << std::endl; //create RX and TX streamers shd::stream_args_t stream_args("fc32"); //complex floats shd::rx_streamer::sptr rx_stream = smini->get_rx_stream(stream_args); shd::tx_streamer::sptr tx_stream = smini->get_tx_stream(stream_args); //------------------------------------------------------------------ // begin messages test //------------------------------------------------------------------ static const shd::dict<std::string, boost::function<bool(shd::smini::multi_smini::sptr, shd::rx_streamer::sptr, shd::tx_streamer::sptr)> > tests = boost::assign::map_list_of ("Test Burst ACK ", &test_burst_ack_message) ("Test Underflow ", &test_underflow_message) ("Test Time Error", &test_time_error_message) ("Test Late Command", &test_late_command_message) ("Test Broken Chain", &test_broken_chain_message) ; //init result counts shd::dict<std::string, size_t> failures, successes; BOOST_FOREACH(const std::string &key, tests.keys()) { failures[key] = 0; successes[key] = 0; } //run the tests, pick at random std::srand((unsigned int) time(NULL)); for (size_t n = 0; n < ntests; n++) { std::string key = tests.keys()[std::rand() % tests.size()]; bool pass = tests[key](smini, rx_stream, tx_stream); flush_async(smini); flush_recv(rx_stream); //store result if (pass) successes[key]++; else failures[key]++; } //print the result summary std::cout << std::endl << "Summary:" << std::endl << std::endl; BOOST_FOREACH(const std::string &key, tests.keys()) { std::cout << boost::format( "%s -> %3u successes, %3u failures" ) % key % successes[key] % failures[key] << std::endl; } //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return 0; }
int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); size_t rxshm_size, txshm_size; bool mimic_active; float mimic_delay; unsigned int iSide, iSwing; // often used loop variables int32_t rx_worker_status = 0; int32_t clrfreq_rx_worker_status = 0; int32_t mute_output = 0; // used if rx_worker error happends int32_t rx_stream_reset_count = 0; int32_t rx_stream_error_count = 0; std::vector<sem_t> sem_rx_vec(nSwings), sem_tx_vec(nSwings); std::vector<uint32_t> state_vec(nSwings, ST_INIT); uint32_t swing; // = SWING0; size_t nSamples_rx, nSamples_tx_pulse, nSamples_pause_after_rx, nSamples_auto_clear_freq, nSamples_rx_total; size_t auto_clear_freq_available = 0; uint32_t npulses, nerrors; ssize_t cmd_status; uint32_t usrp_driver_base_port, ip_part; int32_t connect_retrys = MAX_SOCKET_RETRYS; int32_t sockopt; struct sockaddr_in sockaddr; struct sockaddr_storage client_addr; socklen_t addr_size; uint32_t exit_driver = 0; uint32_t tx_worker_active; uhd::time_spec_t start_time, rx_start_time; // vector of all pulse start times over an integration period std::vector<uhd::time_spec_t> pulse_time_offsets; // vector of the sample index of pulse start times over an integration period std::vector<uint64_t> pulse_sample_idx_offsets; boost::thread_group uhd_threads; boost::thread_group clrfreq_threads; // process config file for port and SHM sizes DEBUG_PRINT("USRP_DRIVER starting to read driver_config.ini\n"); boost::property_tree::ptree pt; boost::property_tree::ini_parser::read_ini("../driver_config.ini", pt); // DEBUG_PRINT("USRP_DRIVER reading rxshm_size\n"); // std::cout << pt.get<std::string>("shm_settings.rxshm_size") << '\n'; rxshm_size = std::stoi(pt.get<std::string>("shm_settings.rxshm_size")); // DEBUG_PRINT("USRP_DRIVER reading txshm_size\n"); txshm_size = std::stoi(pt.get<std::string>("shm_settings.txshm_size")); usrp_driver_base_port = std::stoi(pt.get<std::string>("network_settings.USRPDriverPort")); boost::property_tree::ptree pt_array; DEBUG_PRINT("USRP_DRIVER starting to read array_config.ini\n"); boost::property_tree::ini_parser::read_ini("../array_config.ini", pt_array); mimic_active = std::stof(pt_array.get<std::string>("mimic.mimic_active")) != 0; mimic_delay = std::stof(pt_array.get<std::string>("mimic.mimic_delay")); fprintf(stderr, "read from ini: mimic_active=%d, mimic_delay=%f\n", mimic_active, mimic_delay); init_all_dirs(); // TODO also read usrp_config.ini and get antenna and side information from it. remove antenna input argument. // process command line arguments struct arg_lit *al_help = arg_lit0(NULL, "help", "Prints help information and then exits"); // struct arg_int *ai_ant = arg_intn("a", "antenna", NULL, 1, 2, "Antenna position index for the USRP"); struct arg_int *ai_ant_a = arg_int0("a", "antennaA", NULL, "Antenna position index for the USRP on side A"); struct arg_int *ai_ant_b = arg_int0("b", "antennaB", NULL, "Antenna position index for the USRP on side B"); struct arg_str *as_host = arg_str0("h", "host", NULL, "Hostname or IP address of USRP to control (e.g usrp1)"); struct arg_lit *al_intclk = arg_lit0("i", "intclk", "Select internal clock (default is external)"); struct arg_lit *al_interferometer = arg_lit0("x", "interferometer", "Disable tx_worker for interferometer antennas"); struct arg_end *ae_argend = arg_end(ARG_MAXERRORS); void* argtable[] = {al_help, ai_ant_a, ai_ant_b, as_host, al_intclk, al_interferometer, ae_argend}; double txrate, rxrate, txfreq, rxfreq; double txrate_new, rxrate_new, txfreq_new, rxfreq_new; DEBUG_PRINT("usrp_driver debug mode enabled\n"); if (SUPRESS_UHD_PRINTS) { uhd::msg::register_handler(&uhd_term_message_handler); } nerrors = arg_parse(argc,argv,argtable); if (nerrors > 0) { arg_print_errors(stdout,ae_argend,"usrp_driver"); exit(1); } if (argc == 1) { printf("No arguments found, try running again with --help for more information.\n"); exit(1); } if(al_help->count > 0) { printf("Usage: "); arg_print_syntax(stdout,argtable,"\n"); arg_print_glossary(stdout,argtable," %-25s %s\n"); arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return 0; } unsigned int nSides = ai_ant_a->count + ai_ant_b->count; if( nSides == 0 ) { printf("No antenna index, exiting..."); return 0; } if(as_host->sval == NULL) { printf("Missing usrp host command line argument, exiting..."); return 0; } std::vector<int> antennaVector(nSides); std::vector<uint64_t> channel_numbers; // both sides if( nSides == 2 ) { DEBUG_PRINT("Setting side A: ant_idx %d\n",ai_ant_a->ival[0]); antennaVector[0] = ai_ant_a->ival[0]; channel_numbers.push_back(0); DEBUG_PRINT("Setting side B: ant_idx %d\n",ai_ant_b->ival[0]); antennaVector[1] = ai_ant_b->ival[0]; channel_numbers.push_back(1); } else { // side A if (ai_ant_a->count == 1) { DEBUG_PRINT("Setting side A: ant_idx %d\n",ai_ant_a->ival[0]); antennaVector[0] = ai_ant_a->ival[0]; channel_numbers.push_back(0); // side B } else { DEBUG_PRINT("Setting side B: ant_idx %d\n",ai_ant_b->ival[0]); antennaVector[0] = ai_ant_b->ival[0]; channel_numbers.push_back(1); DEBUG_PRINT("Warning: For one side use DIO output is always on Side A!!!!!!!!!!!!!"); // TODO correct this } } // pointers to shared memory std::vector<std::vector<void *>> shm_rx_vec(nSides, std::vector<void *>( nSwings)); std::vector<std::vector<void *>> shm_tx_vec(nSides, std::vector<void *>( nSwings)); // local buffers for tx and rx std::vector<std::vector<std::complex<int16_t>>> tx_samples(nSides, std::vector<std::complex<int16_t>>(MAX_PULSE_LENGTH,0)); std::vector<std::vector<std::complex<int16_t>>> rx_data_buffer(nSides, std::vector<std::complex<int16_t>>(0)); std::vector<std::vector<std::complex<int16_t>>> rx_auto_clear_freq(nSides, std::vector<std::complex<int16_t>>(0)); std::string usrpargs(as_host->sval[0]); usrpargs = "addr0=" + usrpargs + ",master_clock_rate=200.0e6"; // usrpargs = "addr0=" + usrpargs + ",master_clock_rate=200.0e6,recv_frame_size=50000000"; uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(usrpargs); // usrp->set_rx_subdev_spec(uhd::usrp::subdev_spec_t("A:A B:A")); // usrp->set_tx_subdev_spec(uhd::usrp::subdev_spec_t("A:A B:A")); boost::this_thread::sleep(boost::posix_time::seconds(SETUP_WAIT)); uhd::stream_args_t stream_args("sc16", "sc16"); if (usrp->get_rx_num_channels() < nSides || usrp->get_tx_num_channels() < nSides) { DEBUG_PRINT("ERROR: Number of defined channels (%i) is smaller than avaialable channels:\n usrp->get_rx_num_channels(): %lu \n usrp->get_tx_num_channels(): %lu \n\n", nSides, usrp->get_rx_num_channels(), usrp->get_tx_num_channels()); return -1; } stream_args.channels = channel_numbers; uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args); // TODO: retry uhd connection if fails.. // Determine port from 3rd part of ip (192.168.x.2 => port = base_port + x ) int start_idx = usrpargs.find("."); start_idx = usrpargs.find(".", start_idx+1); int end_idx = usrpargs.find(".", start_idx+1); ip_part = atoi(usrpargs.substr(start_idx+1, end_idx-start_idx-1).c_str()); // initialize rxfe gpio kodiak_init_rxfe(usrp, nSides); // initialize other gpio on usrp init_timing_signals(usrp, mimic_active, nSides); //if(CAPTURE_ERRORS) { // signal(SIGINT, siginthandler); //} // open shared memory buffers and semaphores created by cuda_driver.py // for dual polarization we use antenna numbers 20 to 35 (side is always 0) for(iSwing = 0; iSwing < nSwings; iSwing++) { for(iSide = 0; iSide < nSides; iSide++) { int shm_side = 0; shm_rx_vec[iSide][iSwing] = open_sample_shm(antennaVector[iSide], RXDIR, shm_side, iSwing, rxshm_size); shm_tx_vec[iSide][iSwing] = open_sample_shm(antennaVector[iSide], TXDIR, shm_side, iSwing, txshm_size); DEBUG_PRINT("usrp_driver rx shm addr: %p iSide: %d iSwing: %d\n", shm_rx_vec[iSide][iSwing], iSide, iSwing); if (antennaVector[iSide] < 19 ) { // semaphores only for antennas of first polarization TODO check if this is enough sem_rx_vec[iSwing] = open_sample_semaphore(antennaVector[iSide], iSwing, RXDIR); sem_tx_vec[iSwing] = open_sample_semaphore(antennaVector[iSide], iSwing, TXDIR); } } } if(al_interferometer->count > 0) { DEBUG_PRINT("Disable tx_worker ...\n"); tx_worker_active = 0; } else { tx_worker_active = 1; } if(al_intclk->count > 0) { usrp->set_clock_source("internal"); usrp->set_time_source("internal"); } else { // sync clock with external 10 MHz and PPS DEBUG_PRINT("Set clock: external\n"); usrp->set_clock_source("external", 0); DEBUG_PRINT("Set time: external\n"); usrp->set_time_source("external", 0); DEBUG_PRINT("Done setting time and clock\n"); } while(true) { if(driversock) { close(driverconn); close(driversock); } boost::this_thread::sleep(boost::posix_time::seconds(SETUP_WAIT)); // bind to socket for communication with usrp_server.py: driversock = socket(AF_INET, SOCK_STREAM, 0); if(driversock < 0){ perror("opening stream socket\n"); exit(1); } sockopt = 1; setsockopt(driversock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int32_t)); sockaddr.sin_family = AF_INET; // TODO: maybe limit addr to interface connected to usrp_server sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); fprintf(stderr, "listening on port: %d\n", usrp_driver_base_port + ip_part); sockaddr.sin_port = htons(usrp_driver_base_port + ip_part); if( bind(driversock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0){ perror("binding tx stream socket"); exit(1); } // wait for connection... listen(driversock, 5); // and accept it fprintf(stderr, "waiting for socket connection\n"); addr_size = sizeof(client_addr); driverconn = accept(driversock, (struct sockaddr *) &client_addr, &addr_size); fprintf(stderr, "accepted socket connection\n"); while(true) { // wait for transport endpoint to connect? DEBUG_PRINT("USRP_DRIVER waiting for command\n"); uint8_t command = sock_get_cmd(driverconn, &cmd_status); DEBUG_PRINT("USRP_DRIVER received command, status: %zu\n", cmd_status); // see if socket is closed.. if(cmd_status == 11 || cmd_status == 0 || cmd_status < 0) { DEBUG_PRINT("USRP_DRIVER lost connection to usrp_server, waiting for fresh connection, %d tries remaining\n", connect_retrys); close(driversock); if(connect_retrys-- < 0) { exit(1); } sleep(1); break; } connect_retrys = MAX_SOCKET_RETRYS; switch(command) { case USRP_SETUP: { // receive infomation about a pulse sequence/integration period // transmit/receive center frequenies and sampling rates // number of tx/rx samples // number of pulse sequences per integration period, and pulse start times swing = sock_get_int16( driverconn); DEBUG_PRINT("entering USRP_SETUP command (swing %d)\n", swing); txfreq_new = sock_get_float64(driverconn); rxfreq_new = sock_get_float64(driverconn); txrate_new = sock_get_float64(driverconn); rxrate_new = sock_get_float64(driverconn); npulses = sock_get_uint32(driverconn); nSamples_rx = sock_get_uint64(driverconn); nSamples_pause_after_rx = sock_get_uint64(driverconn); nSamples_auto_clear_freq = sock_get_uint64(driverconn); nSamples_tx_pulse = sock_get_uint64(driverconn); nSamples_rx_total = nSamples_rx + nSamples_pause_after_rx + nSamples_auto_clear_freq; DEBUG_PRINT("USRP_SETUP number of requested rx samples: %d + %d pause + %d auto clear freq\n", (uint32_t) nSamples_rx, nSamples_pause_after_rx, nSamples_auto_clear_freq); DEBUG_PRINT("USRP_SETUP number of requested tx samples per pulse: %d\n", (uint32_t) nSamples_tx_pulse); DEBUG_PRINT("USRP_SETUP existing tx rate : %f (swing %d)\n", txrate, swing); DEBUG_PRINT("USRP_SETUP requested tx rate: %f\n", txrate_new); // resize pulse_sample_idx_offsets.resize(npulses); pulse_time_offsets.resize(npulses); for(uint32_t i = 0; i < npulses; i++) { // DEBUG_PRINT("USRP_SETUP waiting for pulse offset %d of %d\n", i+2, npulses); pulse_sample_idx_offsets[i] = sock_get_uint64(driverconn); // DEBUG_PRINT("USRP_SETUP received %zu pulse offset\n", pulse_sample_idx_offsets[i]); } DEBUG_PRINT("USRP_SETUP resize autoclear freq\n"); // RESIZE LOCAL BUFFERS if(rx_data_buffer[0].size() < nSamples_rx_total) { for(iSide = 0; iSide < nSides; iSide++) { rx_data_buffer[iSide].resize(nSamples_rx_total); } } DEBUG_PRINT("USRP_SETUP resize autoclear freq\n"); if(nSamples_auto_clear_freq != 0 and rx_auto_clear_freq[0].size() < nSamples_auto_clear_freq) { for(iSide = 0; iSide < nSides; iSide++) { rx_auto_clear_freq[iSide].resize(nSamples_auto_clear_freq); } } // TODO use return argument of set_xx to save new rate/freq // if necessary, retune USRP frequency and sampling rate if(rxrate != rxrate_new) { usrp->set_rx_rate(rxrate_new); rxrate = usrp->get_rx_rate(); } if(txrate != txrate_new) { usrp->set_tx_rate(txrate_new); txrate = usrp->get_tx_rate(); } if(rxfreq != rxfreq_new) { for(iSide = 0; iSide < nSides; iSide++) { usrp->set_rx_freq(rxfreq_new, iSide); } rxfreq = usrp->get_rx_freq(); } if(txfreq != txfreq_new) { for(iSide = 0; iSide < nSides; iSide++) { usrp->set_tx_freq(txfreq_new, iSide); } txfreq = usrp->get_tx_freq(); } if(verbose) { std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl; std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl; std::cout << boost::format("Actual TX Freq: %f MHz...") % (usrp->get_tx_freq()/1e6) << std::endl; std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl; } // TODO: set the number of samples in a pulse. this is calculated from the pulse duration and the sampling rate // when do we know this? after USRP_SETUP // create local copy of transmit pulse data from shared memory std::complex<int16_t> *shm_pulseaddr; size_t spb = tx_stream->get_max_num_samps(); size_t pulse_bytes = sizeof(std::complex<int16_t>) * nSamples_tx_pulse; size_t number_of_pulses = pulse_time_offsets.size(); size_t num_samples_per_pulse_with_padding = nSamples_tx_pulse + 2*spb; DEBUG_PRINT("spb %d, pulse length %d samples, pulse with padding %d\n", spb, nSamples_tx_pulse, num_samples_per_pulse_with_padding); // TODO unpack and pad tx sample for (iSide = 0; iSide<nSides; iSide++) { tx_samples[iSide].resize(number_of_pulses * (num_samples_per_pulse_with_padding)); for(uint32_t p_i = 0; p_i < number_of_pulses; p_i++) { shm_pulseaddr = &((std::complex<int16_t> *) shm_tx_vec[iSide][swing])[p_i*nSamples_tx_pulse]; memcpy(&tx_samples[iSide][spb + p_i*(num_samples_per_pulse_with_padding)], shm_pulseaddr, pulse_bytes); } } if(SAVE_RAW_SAMPLES_DEBUG) { FILE *raw_dump_fp; char raw_dump_name[80]; // DEBUG_PRINT("Exporting %i raw tx_samples (%i + 2* %i)\n", num_samples_per_pulse_with_padding, nSamples_tx_pulse, spb); for (iSide =0; iSide < nSides; iSide++){ sprintf(raw_dump_name,"%s/raw_samples_tx_ant_%d.cint16", diag_dir, antennaVector[iSide]); raw_dump_fp = fopen(raw_dump_name, "wb"); fwrite(&tx_samples[iSide][0], sizeof(std::complex<int16_t>),num_samples_per_pulse_with_padding*number_of_pulses, raw_dump_fp); fclose(raw_dump_fp); } } state_vec[swing] = ST_READY; DEBUG_PRINT("changing state_vec[swing] to ST_READY\n"); sock_send_uint8(driverconn, USRP_SETUP); break; } case RXFE_SET: { DEBUG_PRINT("entering RXFE_SET command\n"); RXFESettings rf_settings; rf_settings.amp1 = sock_get_uint8(driverconn); rf_settings.amp2 = sock_get_uint8(driverconn); uint8_t attTimes2 = sock_get_uint8(driverconn); rf_settings.att_05_dB = ( attTimes2 & 0x01 ) != 0; rf_settings.att_1_dB = ( attTimes2 & 0x02 ) != 0; rf_settings.att_2_dB = ( attTimes2 & 0x04 ) != 0; rf_settings.att_4_dB = ( attTimes2 & 0x08 ) != 0; rf_settings.att_8_dB = ( attTimes2 & 0x10 ) != 0; rf_settings.att_16_dB = ( attTimes2 & 0x20 ) != 0; kodiak_set_rxfe(usrp, rf_settings, nSides); sock_send_uint8(driverconn, RXFE_SET); break; } case TRIGGER_PULSE: { swing = sock_get_int16( driverconn); DEBUG_PRINT("entering TRIGGER_PULSE command (swing %d)\n", swing ); if (state_vec[swing] != ST_READY) { sock_send_uint8(driverconn, TRIGGER_BUSY); DEBUG_PRINT("TRIGGER_PULSE busy in state_vec[swing] %d, returning\n", state_vec[swing]); } else { DEBUG_PRINT("TRIGGER_PULSE ready\n"); state_vec[swing] = ST_PULSE; DEBUG_PRINT("TRIGGER_PULSE locking semaphore\n"); lock_semaphore(sem_rx_vec[swing]); lock_semaphore(sem_tx_vec[swing]); DEBUG_PRINT("TRIGGER_PULSE semaphore locked\n"); // create local copy of transmit pulse data from shared memory size_t spb = tx_stream->get_max_num_samps(); size_t pulse_bytes = sizeof(std::complex<int16_t>) * nSamples_tx_pulse; size_t number_of_pulses = pulse_time_offsets.size(); size_t num_samples_per_pulse_with_padding = nSamples_tx_pulse + 2*spb; DEBUG_PRINT("spb %d, pulse length %d samples, pulse with padding %d\n", spb, nSamples_tx_pulse, num_samples_per_pulse_with_padding); // read in time for start of pulse sequence over socket uint32_t pulse_time_full = sock_get_uint32(driverconn); double pulse_time_frac = sock_get_float64(driverconn); start_time = uhd::time_spec_t(pulse_time_full, pulse_time_frac); double tr_to_pulse_delay = sock_get_float64(driverconn); // calculate usrp clock time of the start of each pulse over the integration period // so we can schedule the io (perhaps we will have to move io off of the usrp if it can't keep up) for(uint32_t p_i = 0; p_i < number_of_pulses; p_i++) { double offset_time = pulse_sample_idx_offsets[p_i] / txrate; pulse_time_offsets[p_i] = offset_time_spec(start_time, offset_time); // DEBUG_PRINT("TRIGGER_PULSE pulse time %d is %2.5f\n", p_i, pulse_time_offsets[p_i].get_real_secs()); } DEBUG_PRINT("first TRIGGER_PULSE time is %2.5f and last is %2.5f\n", pulse_time_offsets[0].get_real_secs(), pulse_time_offsets.back().get_real_secs()); rx_start_time = offset_time_spec(start_time, tr_to_pulse_delay/1e6); rx_start_time = offset_time_spec(rx_start_time, pulse_sample_idx_offsets[0]/txrate); // send_timing_for_sequence(usrp, start_time, pulse_times); double pulseLength = nSamples_tx_pulse / txrate; // float debugt = usrp->get_time_now().get_real_secs(); // DEBUG_PRINT("USRP_DRIVER: spawning worker threads at usrp_time %2.4f\n", debugt); DEBUG_PRINT("TRIGGER_PULSE creating rx and tx worker threads on swing %d (nSamples_rx= %d + %d pause + %d auto clear freq )\n", swing,(int) nSamples_rx, nSamples_pause_after_rx, nSamples_auto_clear_freq); // works fine with tx_worker and dio_worker, fails if rx_worker is enabled uhd_threads.create_thread(boost::bind(usrp_rx_worker, usrp, rx_stream, &rx_data_buffer, nSamples_rx_total, rx_start_time, &rx_worker_status)); useconds_t usecs=1000; if (tx_worker_active) { usleep(usecs); uhd_threads.create_thread(boost::bind(usrp_tx_worker, tx_stream, &tx_samples, num_samples_per_pulse_with_padding, start_time, pulse_sample_idx_offsets)); } usleep(usecs); uhd_threads.create_thread(boost::bind(send_timing_for_sequence, usrp, start_time, pulse_time_offsets, pulseLength, mimic_active, mimic_delay, nSides)); sock_send_uint8(driverconn, TRIGGER_PULSE); uhd_threads.join_all(); // wait for transmit threads to finish, drawn from shared memory.. DEBUG_PRINT("TRIGGER_PULSE rx_worker, tx_worker and dio threads on swing %d\n joined.", swing); } break; } case READY_DATA: { swing = sock_get_int16( driverconn); DEBUG_PRINT("READY_DATA command (swing %d), waiting for uhd threads to join back\n", swing); DEBUG_PRINT("READY_DATA unlocking swing a semaphore\n"); unlock_semaphore(sem_rx_vec[swing]); unlock_semaphore(sem_tx_vec[swing]); DEBUG_PRINT("READY_DATA usrp worker threads joined, semaphore unlocked, sending metadata\n"); // TODO: handle multiple channels of data.., use channel index to pick correct swath of memory to copy into shm // rx_worker_status =1; //DEBUG if(rx_worker_status){ fprintf(stderr, "Error in rx_worker. Setting state to %d.\n", rx_worker_status); state_vec[swing] = rx_worker_status; rx_worker_status = 0; mute_output = 1; rx_stream_error_count++; if (rx_stream_reset_count >= MAX_STREAM_RESETS) { fprintf(stderr, "READY_DATA: shutting down usrp_driver to avoid streamer reset overflow (after %dth reset)\n", rx_stream_reset_count); // send all data to server, clean up and exit after that exit_driver = 1; } if((rx_worker_status != RX_WORKER_STREAM_TIME_ERROR) && (rx_stream_error_count > 4)) { // recreate rx_stream unless the error was from sending the stream command too late rx_stream_reset_count++; fprintf(stderr, "READY_DATA: recreating rx_stream %dth time! (buffer overflow will occur for 126th time)\n", rx_stream_reset_count); rx_stream.reset(); rx_stream = usrp->get_rx_stream(stream_args); } auto_clear_freq_available = 0; } else { rx_stream_error_count = 0; auto_clear_freq_available = 1; } DEBUG_PRINT("READY_DATA state: %d, ant: %d, num_samples: %zu\n", state_vec[swing], antennaVector[0], nSamples_rx); sock_send_int32(driverconn, state_vec[swing]); // send status sock_send_int32(driverconn, antennaVector[0]); // send antenna TODO do this for both antennas? sock_send_int32(driverconn, nSamples_rx); // nsamples; send send number of samples // read FAULT status bool fault; for (iSide =0; iSide<nSides; iSide++){ fault = read_FAULT_status_from_control_board(usrp, iSide); } // TODO move this in loop as soon as usrp_server receives both sides sock_send_bool(driverconn, fault); // FAULT status from conrol board if (mute_output) { DEBUG_PRINT("READY_DATA: Filling SHM with zeros (because of rx_worker error) \n"); for (iSide = 0; iSide<nSides; iSide++) { memset(shm_rx_vec[iSide][swing], 0, rxshm_size); std::fill(rx_auto_clear_freq[iSide].begin(), rx_auto_clear_freq[iSide].end(), 0); } mute_output = 0; } else { DEBUG_PRINT("READY_DATA starting copying rx data buffer to shared memory\n"); // regural rx data for (iSide = 0; iSide<nSides; iSide++) { // DEBUG_PRINT("usrp_drivercopy to rx shm addr: %p iSide: %d iSwing: %d\n", shm_rx_vec[iSide][swing], iSide, iSwing); memcpy(shm_rx_vec[iSide][swing], &rx_data_buffer[iSide][0], sizeof(std::complex<int16_t>) * nSamples_rx); } // auto clear freq samples for (iSide = 0; iSide<nSides; iSide++) { for (int iSample = 0; iSample < nSamples_auto_clear_freq; iSample++) { rx_auto_clear_freq[iSide][iSample] = rx_data_buffer[iSide][nSamples_rx+nSamples_pause_after_rx+ iSample]; } } } if(SAVE_RAW_SAMPLES_DEBUG) { FILE *raw_dump_fp; char raw_dump_name[80]; for (iSide=0; iSide<nSides; iSide++) { sprintf(raw_dump_name,"%s/raw_samples_rx_ant_%d.cint16", diag_dir, antennaVector[iSide]); raw_dump_fp = fopen(raw_dump_name, "wb"); fwrite(&rx_data_buffer[iSide], sizeof(std::complex<int16_t>), nSamples_rx_total, raw_dump_fp); fclose(raw_dump_fp); } } DEBUG_PRINT("READY_DATA finished copying rx data buffer to shared memory\n"); state_vec[swing] = ST_READY; DEBUG_PRINT("changing state_vec[swing] to ST_READY\n"); DEBUG_PRINT("READY_DATA returning command success \n"); sock_send_uint8(driverconn, READY_DATA); break; } case UHD_GETTIME: { DEBUG_PRINT("entering UHD_GETTIME command\n"); start_time = usrp->get_time_now(); uint32_t real_time = start_time.get_real_secs(); double frac_time = start_time.get_frac_secs(); sock_send_uint32(driverconn, real_time); sock_send_float64(driverconn, frac_time); DEBUG_PRINT("UHD_GETTIME current UHD time: %d %.2f command\n", real_time, frac_time); sock_send_uint8(driverconn, UHD_GETTIME); break; } // command to reset time, sync time with external PPS pulse case UHD_SYNC: { DEBUG_PRINT("entering UHD_SYNC command\n"); // if --intclk flag passed to usrp_driver, set clock source as internal and do not sync time if(al_intclk->count > 0) { usrp->set_time_now(uhd::time_spec_t(0.0)); } else { /* const uhd::time_spec_t last_pps_time = usrp->get_time_last_pps(); while (last_pps_time == usrp->get_time_last_pps()) { boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } usrp->set_time_next_pps(uhd::time_spec_t(0.0)); boost::this_thread::sleep(boost::posix_time::milliseconds(1100)); */ DEBUG_PRINT("Start setting unknown pps\n"); usrp->set_time_unknown_pps(uhd::time_spec_t(11.0)); DEBUG_PRINT("end setting unknown pps\n"); } sock_send_uint8(driverconn, UHD_SYNC); break; } case AUTOCLRFREQ: { // has to be called after GET_DATA and before USRP_SETUP DEBUG_PRINT("entering getting auto clear freq command\n"); // uint32_t num_clrfreq_samples = sock_get_uint32(driverconn); iSide = 0;// TODO both sides! if (auto_clear_freq_available) { DEBUG_PRINT("AUTOCLRFREQ samples sending %d samples for antenna %d...\n", rx_auto_clear_freq[iSide].size(),antennaVector[iSide]); sock_send_int32(driverconn, (int32_t) antennaVector[iSide]); sock_send_uint32(driverconn, (uint32_t) rx_auto_clear_freq[iSide].size()); // send samples send(driverconn, &rx_auto_clear_freq[iSide][0], sizeof(std::complex<short int>) * rx_auto_clear_freq[iSide].size() , 0); } else { sock_send_int32(driverconn, (int32_t) -1); } sock_send_uint8(driverconn, AUTOCLRFREQ); break; } case CLRFREQ: { DEBUG_PRINT("entering CLRFREQ command\n"); uint32_t num_clrfreq_samples = sock_get_uint32(driverconn); uint32_t clrfreq_time_full = sock_get_uint32(driverconn); double clrfreq_time_frac = sock_get_float64(driverconn); double clrfreq_cfreq = sock_get_float64(driverconn); double clrfreq_rate = sock_get_float64(driverconn); std::vector<std::vector<std::complex<int16_t>>> clrfreq_data_buffer(nSides, std::vector<std::complex<int16_t>>(num_clrfreq_samples)); uint32_t real_time; double frac_time; DEBUG_PRINT("CLRFREQ time: %d . %.2f \n", clrfreq_time_full, clrfreq_time_frac); DEBUG_PRINT("CLRFREQ rate: %.2f, CLRFREQ_nsamples %d, freq: %.2f\n", clrfreq_rate, num_clrfreq_samples, clrfreq_cfreq); uhd::time_spec_t clrfreq_start_time = uhd::time_spec_t(clrfreq_time_full, clrfreq_time_frac); real_time = clrfreq_start_time.get_real_secs(); frac_time = clrfreq_start_time.get_frac_secs(); DEBUG_PRINT("CLRFREQ UHD clrfreq target time: %d %.2f \n", real_time, frac_time); // TODO: only set rate if it is different! if(rxrate != clrfreq_rate) { usrp->set_rx_rate(clrfreq_rate); rxrate = usrp->get_rx_rate(); clrfreq_rate = rxrate; } DEBUG_PRINT("CLRFREQ actual rate: %.2f\n", clrfreq_rate); //clrfreq_cfreq = usrp->get_rx_freq(); //DEBUG_PRINT("CLRFREQ actual freq: %.2f\n", clrfreq_cfreq); clrfreq_threads.create_thread(boost::bind(usrp_rx_worker, usrp, rx_stream, &clrfreq_data_buffer, num_clrfreq_samples, clrfreq_start_time, &clrfreq_rx_worker_status)); clrfreq_threads.join_all(); if(clrfreq_rx_worker_status){ fprintf(stderr, "Error in clrfreq_rx_worker, resetting rx_stream: %d.\n", clrfreq_rx_worker_status); rx_stream_reset_count++; fprintf(stderr, "CLRFREQ: recreating rx_stream %dth time! (buffer overflow will occur for 126th time)\n", rx_stream_reset_count); rx_stream.reset(); rx_stream = usrp->get_rx_stream(stream_args); } if (rx_stream_reset_count >= MAX_STREAM_RESETS) { fprintf(stderr, "CLRFREQ: shutting down usrp_driver to avoid streamer reset overflow (after %dth reset)\n", rx_stream_reset_count); // finish clrfreq command, then clean up and exit to avoid buffer overflow exit_driver = 1; } DEBUG_PRINT("CLRFREQ received samples, relaying %d samples back...\n", num_clrfreq_samples); sock_send_int32(driverconn, (int32_t) antennaVector[0]); // TODO both sides? sock_send_float64(driverconn, clrfreq_rate); // send back samples send(driverconn, &clrfreq_data_buffer[0][0], sizeof(std::complex<short int>) * num_clrfreq_samples, 0); //for(uint32_t i = 0; i < num_clrfreq_samples; i++) { //DEBUG_PRINT("sending %d - %d\n", i, clrfreq_data_buffer[0][i]); // sock_send_cshort(driverconn, clrfreq_data_buffer[0][i]); // } DEBUG_PRINT("CLRFREQ samples sent for antenna %d...\n", antennaVector[0]); // restore usrp rates usrp->set_rx_rate(rxrate); usrp->set_rx_freq(rxfreq); sock_send_uint8(driverconn, CLRFREQ); start_time = usrp->get_time_now(); real_time = start_time.get_real_secs(); frac_time = start_time.get_frac_secs(); DEBUG_PRINT("CLRFREQ finished at UHD time: %d %.2f \n", real_time, frac_time); break; } case EXIT: { DEBUG_PRINT("entering EXIT command\n"); exit_driver = 1; break; } default: { printf("USRP_DRIVER unrecognized command: %d, %c, exiting..\n", command, command); sleep(10); exit(1); break; } } if (not check_clock_lock(usrp)) { fprintf(stderr, "Error: Lost clock for USRP: %s\n ", as_host->sval[0]); exit_driver = 1; } // clean exit if (exit_driver) { DEBUG_PRINT("Shutting down driver\n"); close(driverconn); for(iSide = 0; iSide < nSides; iSide++) { for(iSwing = 0; iSwing < nSwings; iSwing++) { // fill SHM with zeros memset(shm_rx_vec[iSide][iSwing], 0, rxshm_size); memset(shm_tx_vec[iSide][iSwing], 0, txshm_size); munmap(shm_rx_vec[iSide][iSwing], rxshm_size); munmap(shm_tx_vec[iSide][iSwing], txshm_size); sem_close(&sem_rx_vec[iSwing]); sem_close(&sem_tx_vec[iSwing]); } } // TODO: close usrp streams? // sock_send_uint8(driverconn, EXIT); exit(1); } } } return 0; }
/*********************************************************************** * 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(); } }
/*********************************************************************** * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string args; double tx_wave_freq, tx_wave_ampl, rx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("verbose", "enable some verbose") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") ("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz") ("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)") ("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)") ("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz") ("nsamps", po::value<size_t>(&nsamps)->default_value(default_num_samps), "Samples per data capture") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("USRP Generate TX DC Offset Calibration Table %s") % desc << std::endl; std::cout << "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n" << std::endl; return ~0; } //create a usrp device std::cout << std::endl; 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); //set the antennas to cal if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate."); } usrp->set_rx_antenna("CAL"); usrp->set_tx_antenna("CAL"); //fail if daughterboard has no serial check_for_empty_serial(usrp, "TX", "tx", args); //set optimum defaults set_optimum_defaults(usrp); //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //create a transmitter thread boost::thread_group threads; threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_freq, tx_wave_ampl)); //re-usable buffer for samples std::vector<samp_type> buff; //store the results here std::vector<result_t> results; if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6; if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6; for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){ const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset); //frequency constants for this tune event 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_dc_freq = actual_tx_freq - actual_rx_freq; //capture initial uncorrected value usrp->set_tx_dc_offset(std::complex<double>(0, 0)); capture_samples(usrp, rx_stream, buff, nsamps); const double initial_dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate); //bounds and results from searching double dc_i_start = -.01, dc_i_stop = .01, dc_i_step; double dc_q_start = -.01, dc_q_stop = .01, dc_q_step; double lowest_offset = 0, best_dc_i = 0, best_dc_q = 0; for (size_t i = 0; i < num_search_iters; i++){ dc_i_step = (dc_i_stop - dc_i_start)/(num_search_steps-1); dc_q_step = (dc_q_stop - dc_q_start)/(num_search_steps-1); for (double dc_i = dc_i_start; dc_i <= dc_i_stop + dc_i_step/2; dc_i += dc_i_step){ for (double dc_q = dc_q_start; dc_q <= dc_q_stop + dc_q_step/2; dc_q += dc_q_step){ const std::complex<double> correction(dc_i, dc_q); usrp->set_tx_dc_offset(correction); //receive some samples capture_samples(usrp, rx_stream, buff, nsamps); const double dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate); if (dc_dbrms < lowest_offset){ lowest_offset = dc_dbrms; best_dc_i = dc_i; best_dc_q = dc_q; } }} //std::cout << "best_dc_i " << best_dc_i << std::endl; //std::cout << "best_dc_q " << best_dc_q << std::endl; //std::cout << "lowest_offset " << lowest_offset << std::endl; dc_i_start = best_dc_i - dc_i_step; dc_i_stop = best_dc_i + dc_i_step; dc_q_start = best_dc_q - dc_q_step; dc_q_stop = best_dc_q + dc_q_step; } if (lowest_offset < initial_dc_dbrms){ //most likely valid, keep result result_t result; result.freq = tx_lo; result.real_corr = best_dc_i; result.imag_corr = best_dc_q; result.best = lowest_offset; result.delta = initial_dc_dbrms - lowest_offset; results.push_back(result); if (vm.count("verbose")){ std::cout << boost::format("TX DC: %f MHz: lowest offset %f dB, corrected %f dB") % (tx_lo/1e6) % result.best % result.delta << std::endl; } else std::cout << "." << std::flush; } } std::cout << std::endl; //stop the transmitter threads.interrupt_all(); threads.join_all(); store_results(usrp, results, "TX", "tx", "dc"); return 0; }
/*********************************************************************** * Main function **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //transmit variables to be set by po std::string tx_args, wave_type, tx_ant, tx_subdev, ref, otw, tx_channels; double tx_rate, tx_freq, tx_gain, wave_freq, tx_bw; float ampl; //receive variables to be set by po std::string rx_args, file, type, rx_ant, rx_subdev, rx_channels; size_t total_num_samps, spb; double rx_rate, rx_freq, rx_gain, rx_bw; double settling; //setup the program options po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("tx-args", po::value<std::string>(&tx_args)->default_value(""), "uhd transmit device address args") ("rx-args", po::value<std::string>(&rx_args)->default_value(""), "uhd receive device address args") ("file", po::value<std::string>(&file)->default_value("usrp_samples.dat"), "name of the file to write binary samples to") ("type", po::value<std::string>(&type)->default_value("short"), "sample type in file: double, float, or short") ("nsamps", po::value<size_t>(&total_num_samps)->default_value(0), "total number of samples to receive") ("settling", po::value<double>(&settling)->default_value(double(0.2)), "settling time (seconds) before receiving") ("spb", po::value<size_t>(&spb)->default_value(0), "samples per buffer, 0 for default") ("tx-rate", po::value<double>(&tx_rate), "rate of transmit outgoing samples") ("rx-rate", po::value<double>(&rx_rate), "rate of receive incoming samples") ("tx-freq", po::value<double>(&tx_freq), "transmit RF center frequency in Hz") ("rx-freq", po::value<double>(&rx_freq), "receive RF center frequency in Hz") ("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of the waveform [0 to 0.7]") ("tx-gain", po::value<double>(&tx_gain), "gain for the transmit RF chain") ("rx-gain", po::value<double>(&rx_gain), "gain for the receive RF chain") ("tx-ant", po::value<std::string>(&tx_ant), "transmit antenna selection") ("rx-ant", po::value<std::string>(&rx_ant), "receive antenna selection") ("tx-subdev", po::value<std::string>(&tx_subdev), "transmit subdevice specification") ("rx-subdev", po::value<std::string>(&rx_subdev), "receive subdevice specification") ("tx-bw", po::value<double>(&tx_bw), "analog transmit filter bandwidth in Hz") ("rx-bw", po::value<double>(&rx_bw), "analog receive filter bandwidth in Hz") ("wave-type", po::value<std::string>(&wave_type)->default_value("CONST"), "waveform type (CONST, SQUARE, RAMP, SINE)") ("wave-freq", po::value<double>(&wave_freq)->default_value(0), "waveform frequency in Hz") ("ref", po::value<std::string>(&ref)->default_value("internal"), "clock reference (internal, external, mimo)") ("otw", po::value<std::string>(&otw)->default_value("sc16"), "specify the over-the-wire sample mode") ("tx-channels", po::value<std::string>(&tx_channels)->default_value("0"), "which TX channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)") ("rx-channels", po::value<std::string>(&rx_channels)->default_value("0"), "which RX channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)") ("tx-int-n", "tune USRP TX with integer-N tuning") ("rx-int-n", "tune USRP RX with integer-N tuning") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("UHD TXRX Loopback to File %s") % desc << std::endl; return ~0; } //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the transmit usrp device with: %s...") % tx_args << std::endl; uhd::usrp::multi_usrp::sptr tx_usrp = uhd::usrp::multi_usrp::make(tx_args); std::cout << std::endl; std::cout << boost::format("Creating the receive usrp device with: %s...") % rx_args << std::endl; uhd::usrp::multi_usrp::sptr rx_usrp = uhd::usrp::multi_usrp::make(rx_args); //always select the subdevice first, the channel mapping affects the other settings if (vm.count("tx-subdev")) tx_usrp->set_tx_subdev_spec(tx_subdev); if (vm.count("rx-subdev")) rx_usrp->set_rx_subdev_spec(rx_subdev); //detect which channels to use std::vector<std::string> tx_channel_strings; std::vector<size_t> tx_channel_nums; boost::split(tx_channel_strings, tx_channels, boost::is_any_of("\"',")); for(size_t ch = 0; ch < tx_channel_strings.size(); ch++){ size_t chan = std::stoi(tx_channel_strings[ch]); if(chan >= tx_usrp->get_tx_num_channels()){ throw std::runtime_error("Invalid TX channel(s) specified."); } else tx_channel_nums.push_back(std::stoi(tx_channel_strings[ch])); } std::vector<std::string> rx_channel_strings; std::vector<size_t> rx_channel_nums; boost::split(rx_channel_strings, rx_channels, boost::is_any_of("\"',")); for(size_t ch = 0; ch < rx_channel_strings.size(); ch++){ size_t chan = std::stoi(rx_channel_strings[ch]); if(chan >= rx_usrp->get_rx_num_channels()){ throw std::runtime_error("Invalid RX channel(s) specified."); } else rx_channel_nums.push_back(std::stoi(rx_channel_strings[ch])); } //Lock mboard clocks tx_usrp->set_clock_source(ref); rx_usrp->set_clock_source(ref); std::cout << boost::format("Using TX Device: %s") % tx_usrp->get_pp_string() << std::endl; std::cout << boost::format("Using RX Device: %s") % rx_usrp->get_pp_string() << std::endl; //set the transmit sample rate if (not vm.count("tx-rate")){ std::cerr << "Please specify the transmit sample rate with --tx-rate" << std::endl; return ~0; } std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; tx_usrp->set_tx_rate(tx_rate); std::cout << boost::format("Actual TX Rate: %f Msps...") % (tx_usrp->get_tx_rate()/1e6) << std::endl << std::endl; //set the receive sample rate if (not vm.count("rx-rate")){ std::cerr << "Please specify the sample rate with --rx-rate" << std::endl; return ~0; } std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl; rx_usrp->set_rx_rate(rx_rate); std::cout << boost::format("Actual RX Rate: %f Msps...") % (rx_usrp->get_rx_rate()/1e6) << std::endl << std::endl; //set the transmit center frequency if (not vm.count("tx-freq")){ std::cerr << "Please specify the transmit center frequency with --tx-freq" << std::endl; return ~0; } for(size_t ch = 0; ch < tx_channel_nums.size(); ch++) { size_t channel = tx_channel_nums[ch]; if (tx_channel_nums.size() > 1) { std::cout << "Configuring TX Channel " << channel << std::endl; } std::cout << boost::format("Setting TX Freq: %f MHz...") % (tx_freq/1e6) << std::endl; uhd::tune_request_t tx_tune_request(tx_freq); if(vm.count("tx-int-n")) tx_tune_request.args = uhd::device_addr_t("mode_n=integer"); tx_usrp->set_tx_freq(tx_tune_request, channel); std::cout << boost::format("Actual TX Freq: %f MHz...") % (tx_usrp->get_tx_freq(channel)/1e6) << std::endl << std::endl; //set the rf gain if (vm.count("tx-gain")){ std::cout << boost::format("Setting TX Gain: %f dB...") % tx_gain << std::endl; tx_usrp->set_tx_gain(tx_gain, channel); std::cout << boost::format("Actual TX Gain: %f dB...") % tx_usrp->get_tx_gain(channel) << std::endl << std::endl; } //set the analog frontend filter bandwidth if (vm.count("tx-bw")){ std::cout << boost::format("Setting TX Bandwidth: %f MHz...") % tx_bw << std::endl; tx_usrp->set_tx_bandwidth(tx_bw, channel); std::cout << boost::format("Actual TX Bandwidth: %f MHz...") % tx_usrp->get_tx_bandwidth(channel) << std::endl << std::endl; } //set the antenna if (vm.count("tx-ant")) tx_usrp->set_tx_antenna(tx_ant, channel); } for(size_t ch = 0; ch < rx_channel_nums.size(); ch++) { size_t channel = rx_channel_nums[ch]; if (rx_channel_nums.size() > 1) { std::cout << "Configuring RX Channel " << channel << std::endl; } //set the receive center frequency if (not vm.count("rx-freq")){ std::cerr << "Please specify the center frequency with --rx-freq" << std::endl; return ~0; } std::cout << boost::format("Setting RX Freq: %f MHz...") % (rx_freq/1e6) << std::endl; uhd::tune_request_t rx_tune_request(rx_freq); if(vm.count("rx-int-n")) rx_tune_request.args = uhd::device_addr_t("mode_n=integer"); rx_usrp->set_rx_freq(rx_tune_request, channel); std::cout << boost::format("Actual RX Freq: %f MHz...") % (rx_usrp->get_rx_freq(channel)/1e6) << std::endl << std::endl; //set the receive rf gain if (vm.count("rx-gain")){ std::cout << boost::format("Setting RX Gain: %f dB...") % rx_gain << std::endl; rx_usrp->set_rx_gain(rx_gain, channel); std::cout << boost::format("Actual RX Gain: %f dB...") % rx_usrp->get_rx_gain(channel) << std::endl << std::endl; } //set the receive analog frontend filter bandwidth if (vm.count("rx-bw")){ std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % (rx_bw/1e6) << std::endl; rx_usrp->set_rx_bandwidth(rx_bw, channel); std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % (rx_usrp->get_rx_bandwidth(channel)/1e6) << std::endl << std::endl; } } //set the receive antenna if (vm.count("ant")) rx_usrp->set_rx_antenna(rx_ant); //for the const wave, set the wave freq for small samples per period if (wave_freq == 0 and wave_type == "CONST"){ wave_freq = tx_usrp->get_tx_rate()/2; } //error when the waveform is not possible to generate if (std::abs(wave_freq) > tx_usrp->get_tx_rate()/2){ throw std::runtime_error("wave freq out of Nyquist zone"); } if (tx_usrp->get_tx_rate()/std::abs(wave_freq) > wave_table_len/2){ throw std::runtime_error("wave freq too small for table"); } //pre-compute the waveform values const wave_table_class wave_table(wave_type, ampl); const size_t step = boost::math::iround(wave_freq/tx_usrp->get_tx_rate() * wave_table_len); size_t index = 0; //create a transmit streamer //linearly map channels (index0 = channel0, index1 = channel1, ...) uhd::stream_args_t stream_args("fc32", otw); stream_args.channels = tx_channel_nums; uhd::tx_streamer::sptr tx_stream = tx_usrp->get_tx_stream(stream_args); //allocate a buffer which we re-use for each channel if (spb == 0) spb = tx_stream->get_max_num_samps()*10; std::vector<std::complex<float> > buff(spb); int num_channels = tx_channel_nums.size(); //setup the metadata flags 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.5); //give us 0.5 seconds to fill the tx buffers //Check Ref and LO Lock detect std::vector<std::string> tx_sensor_names, rx_sensor_names; tx_sensor_names = tx_usrp->get_tx_sensor_names(0); if (std::find(tx_sensor_names.begin(), tx_sensor_names.end(), "lo_locked") != tx_sensor_names.end()) { uhd::sensor_value_t lo_locked = tx_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()); } rx_sensor_names = rx_usrp->get_rx_sensor_names(0); if (std::find(rx_sensor_names.begin(), rx_sensor_names.end(), "lo_locked") != rx_sensor_names.end()) { uhd::sensor_value_t lo_locked = rx_usrp->get_rx_sensor("lo_locked",0); std::cout << boost::format("Checking RX: %s ...") % lo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(lo_locked.to_bool()); } tx_sensor_names = tx_usrp->get_mboard_sensor_names(0); if ((ref == "mimo") and (std::find(tx_sensor_names.begin(), tx_sensor_names.end(), "mimo_locked") != tx_sensor_names.end())) { uhd::sensor_value_t mimo_locked = tx_usrp->get_mboard_sensor("mimo_locked",0); std::cout << boost::format("Checking TX: %s ...") % mimo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(mimo_locked.to_bool()); } if ((ref == "external") and (std::find(tx_sensor_names.begin(), tx_sensor_names.end(), "ref_locked") != tx_sensor_names.end())) { uhd::sensor_value_t ref_locked = tx_usrp->get_mboard_sensor("ref_locked",0); std::cout << boost::format("Checking TX: %s ...") % ref_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(ref_locked.to_bool()); } rx_sensor_names = rx_usrp->get_mboard_sensor_names(0); if ((ref == "mimo") and (std::find(rx_sensor_names.begin(), rx_sensor_names.end(), "mimo_locked") != rx_sensor_names.end())) { uhd::sensor_value_t mimo_locked = rx_usrp->get_mboard_sensor("mimo_locked",0); std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(mimo_locked.to_bool()); } if ((ref == "external") and (std::find(rx_sensor_names.begin(), rx_sensor_names.end(), "ref_locked") != rx_sensor_names.end())) { uhd::sensor_value_t ref_locked = rx_usrp->get_mboard_sensor("ref_locked",0); std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(ref_locked.to_bool()); } if (total_num_samps == 0){ std::signal(SIGINT, &sig_int_handler); std::cout << "Press Ctrl + C to stop streaming..." << std::endl; } //reset usrp time to prepare for transmit/receive std::cout << boost::format("Setting device timestamp to 0...") << std::endl; tx_usrp->set_time_now(uhd::time_spec_t(0.0)); //start transmit worker thread boost::thread_group transmit_thread; transmit_thread.create_thread(boost::bind(&transmit_worker, buff, wave_table, tx_stream, md, step, index, num_channels)); //recv to file if (type == "double") recv_to_file<std::complex<double> >(rx_usrp, "fc64", otw, file, spb, total_num_samps, settling, rx_channel_nums); else if (type == "float") recv_to_file<std::complex<float> >(rx_usrp, "fc32", otw, file, spb, total_num_samps, settling, rx_channel_nums); else if (type == "short") recv_to_file<std::complex<short> >(rx_usrp, "sc16", otw, file, spb, total_num_samps, settling, rx_channel_nums); else { //clean up transmit worker stop_signal_called = true; transmit_thread.join_all(); throw std::runtime_error("Unknown type " + type); } //clean up transmit worker stop_signal_called = true; transmit_thread.join_all(); //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return EXIT_SUCCESS; }
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_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //variables to be set by po std::string args, file, ant, subdev, ref; size_t total_num_samps; double rate, freq, gain, bw; std::string addr, port; //setup the program options 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") ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive") ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples") ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz") ("gain", po::value<double>(&gain)->default_value(0), "gain for the RF chain") ("ant", po::value<std::string>(&ant), "daughterboard antenna selection") ("subdev", po::value<std::string>(&subdev), "daughterboard subdevice specification") ("bw", po::value<double>(&bw), "daughterboard IF filter bandwidth in Hz") ("port", po::value<std::string>(&port)->default_value("7124"), "server udp port") ("addr", po::value<std::string>(&addr)->default_value("192.168.1.10"), "resolvable server address") ("ref", po::value<std::string>(&ref)->default_value("internal"), "waveform type (internal, external, mimo)") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("UHD RX to UDP %s") % desc << std::endl; return ~0; } //create a usrp device std::cout << std::endl; 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); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; //Lock mboard clocks usrp->set_clock_source(ref); //set the rx sample rate 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 rx center frequency std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl; usrp->set_rx_freq(freq); std::cout << boost::format("Actual RX Freq: %f Mhz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl; //set the rx rf gain std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl; usrp->set_rx_gain(gain); std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl; //set the IF filter bandwidth if (vm.count("bw")){ std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl; usrp->set_rx_bandwidth(bw); std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl; } //set the antenna if (vm.count("ant")) usrp->set_rx_antenna(ant); boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time //Check Ref and LO Lock detect std::vector<std::string> sensor_names; sensor_names = usrp->get_rx_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_rx_sensor("lo_locked",0); std::cout << boost::format("Checking RX: %s ...") % lo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(lo_locked.to_bool()); } sensor_names = usrp->get_mboard_sensor_names(0); if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) { uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0); std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(mimo_locked.to_bool()); } if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) { uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0); std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(ref_locked.to_bool()); } //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //setup streaming uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); stream_cmd.num_samps = total_num_samps; stream_cmd.stream_now = true; usrp->issue_stream_cmd(stream_cmd); //loop until total number of samples reached size_t num_acc_samps = 0; //number of accumulated samples uhd::rx_metadata_t md; std::vector<std::complex<float> > buff(rx_stream->get_max_num_samps()); uhd::transport::udp_simple::sptr udp_xport = uhd::transport::udp_simple::make_connected(addr, port); while(num_acc_samps < total_num_samps){ size_t num_rx_samps = rx_stream->recv( &buff.front(), buff.size(), md ); //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: if (num_acc_samps == 0) continue; std::cout << boost::format( "Got timeout before all samples received, possible packet loss, exiting loop..." ) << std::endl; goto done_loop; default: std::cout << boost::format( "Got error code 0x%x, exiting loop..." ) % md.error_code << std::endl; goto done_loop; } //send complex single precision floating point samples over udp udp_xport->send(boost::asio::buffer(buff, num_rx_samps*sizeof(buff.front()))); num_acc_samps += num_rx_samps; } done_loop: //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return 0; }
int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::set_thread_priority_safe(); //variables to be set by po std::string args, ant, subdev, ref; size_t num_bins; double rate, freq, gain, bw, frame_rate; float ref_lvl, dyn_rng; //setup the program options 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") // hardware parameters ("rate", po::value<double>(&rate), "rate of incoming samples (sps)") ("freq", po::value<double>(&freq), "RF center frequency in Hz") ("gain", po::value<double>(&gain), "gain for the RF chain") ("ant", po::value<std::string>(&ant), "daughterboard antenna selection") ("subdev", po::value<std::string>(&subdev), "daughterboard subdevice specification") ("bw", po::value<double>(&bw), "daughterboard IF filter bandwidth in Hz") // display parameters ("num-bins", po::value<size_t>(&num_bins)->default_value(512), "the number of bins in the DFT") ("frame-rate", po::value<double>(&frame_rate)->default_value(5), "frame rate of the display (fps)") ("ref-lvl", po::value<float>(&ref_lvl)->default_value(0), "reference level for the display (dB)") ("dyn-rng", po::value<float>(&dyn_rng)->default_value(60), "dynamic range for the display (dB)") ("ref", po::value<std::string>(&ref)->default_value("internal"), "waveform type (internal, external, mimo)") ("int-n", "tune USRP with integer-N tuning") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help") or not vm.count("rate")){ std::cout << boost::format("UHD RX ASCII Art DFT %s") % desc << std::endl; return EXIT_FAILURE; } //create a usrp device std::cout << std::endl; 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); //Lock mboard clocks usrp->set_clock_source(ref); //always select the subdevice first, the channel mapping affects the other settings if (vm.count("subdev")) usrp->set_rx_subdev_spec(subdev); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; //set the sample rate if (not vm.count("rate")){ std::cerr << "Please specify the sample rate with --rate" << std::endl; return EXIT_FAILURE; } 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 if (not vm.count("freq")){ std::cerr << "Please specify the center frequency with --freq" << std::endl; return EXIT_FAILURE; } std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl; uhd::tune_request_t tune_request(freq); if(vm.count("int-n")) tune_request.args = uhd::device_addr_t("mode_n=integer"); usrp->set_rx_freq(tune_request); std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl; //set the rf gain if (vm.count("gain")){ std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl; usrp->set_rx_gain(gain); std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl; } //set the IF filter bandwidth if (vm.count("bw")){ std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl; usrp->set_rx_bandwidth(bw); std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl; } //set the antenna if (vm.count("ant")) usrp->set_rx_antenna(ant); boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time //Check Ref and LO Lock detect std::vector<std::string> sensor_names; sensor_names = usrp->get_rx_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_rx_sensor("lo_locked",0); std::cout << boost::format("Checking RX: %s ...") % lo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(lo_locked.to_bool()); } sensor_names = usrp->get_mboard_sensor_names(0); if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) { uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0); std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(mimo_locked.to_bool()); } if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) { uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0); std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl; UHD_ASSERT_THROW(ref_locked.to_bool()); } //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //allocate recv buffer and metatdata uhd::rx_metadata_t md; std::vector<std::complex<float> > buff(num_bins); //------------------------------------------------------------------ //-- Initialize //------------------------------------------------------------------ initscr(); //curses init rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); boost::system_time next_refresh = boost::get_system_time(); //------------------------------------------------------------------ //-- Main loop //------------------------------------------------------------------ while (true){ //read a buffer's worth of samples every iteration size_t num_rx_samps = rx_stream->recv( &buff.front(), buff.size(), md ); if (num_rx_samps != buff.size()) continue; //check and update the display refresh condition if (boost::get_system_time() < next_refresh) continue; next_refresh = boost::get_system_time() + boost::posix_time::microseconds(long(1e6/frame_rate)); //calculate the dft and create the ascii art frame acsii_art_dft::log_pwr_dft_type lpdft( acsii_art_dft::log_pwr_dft(&buff.front(), num_rx_samps) ); std::string frame = acsii_art_dft::dft_to_plot( lpdft, COLS, LINES, usrp->get_rx_rate(), usrp->get_rx_freq(), dyn_rng, ref_lvl ); //curses screen handling: clear and print frame clear(); printw("%s", frame.c_str()); //curses key handling: no timeout, any key to exit timeout(0); int ch = getch(); if (ch != KEY_RESIZE and ch != ERR) break; } //------------------------------------------------------------------ //-- Cleanup //------------------------------------------------------------------ rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); endwin(); //curses done //finished std::cout << std::endl << "Done!" << std::endl << std::endl; return EXIT_SUCCESS; }
int cuhd_open_(char *args, void **h, bool create_thread_gain, bool tx_gain_same_rx) { *h = NULL; /* Set priority to UHD threads */ uhd::set_thread_priority_safe(); /* Get multiusrp handler */ cuhd_handler *handler = new cuhd_handler(); std::string _args = std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args);// + ", recv_frame_size=9232,num_recv_frames=64,send_frame_size=9232,num_send_frames=64"); /* Initialize rx and tx stremers */ std::string otw, cpu; otw = "sc16"; cpu = "fc32"; uhd::stream_args_t stream_args(cpu, otw); handler->rx_stream = handler->usrp->get_rx_stream(stream_args); handler->tx_stream = handler->usrp->get_tx_stream(stream_args); handler->rx_nof_samples = handler->rx_stream->get_max_num_samps(); handler->tx_nof_samples = handler->tx_stream->get_max_num_samps(); handler->tx_gain_same_rx = tx_gain_same_rx; handler->tx_rx_gain_offset = 0.0; handler->rx_gain_range = handler->usrp->get_rx_gain_range(); handler->tx_gain_range = handler->usrp->get_tx_gain_range(); /* Create auxiliary thread and mutexes for AGC */ if (create_thread_gain) { if (pthread_mutex_init(&handler->mutex, NULL)) { return -1; } if (pthread_cond_init(&handler->cond, NULL)) { return -1; } if (pthread_create(&handler->thread_gain, NULL, thread_gain_fcn, handler)) { perror("pthread_create"); return -1; } } /* Find out if the master clock rate is configurable */ double cur_clock = handler->usrp->get_master_clock_rate(); printf("Trying to dynamically change Master clock...\n"); handler->usrp->set_master_clock_rate(cur_clock/2); if (handler->usrp->get_master_clock_rate() == cur_clock) { handler->dynamic_rate = false; /* Master clock rate is not configurable. Check if it is compatible with LTE */ int cur_clock_i = (int) cur_clock; if (cur_clock_i % 1920000) { fprintf(stderr, "Error: LTE sampling rates are not supported. Master clock rate is %.1f MHz\n", cur_clock/1e6); return -1; } else { printf("Master clock is not configurable. Using standard symbol sizes and sampling rates.\n"); srslte_use_standard_symbol_size(true); } } else { printf("Master clock is configurable. Using reduced symbol sizes and sampling rates.\n"); handler->dynamic_rate = true; } *h = handler; return 0; }
/*********************************************************************** * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string args; double tx_wave_ampl, tx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("verbose", "enable some verbose") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("tx_offset", po::value<double>(&tx_offset)->default_value(.9344e6), "TX LO offset from the RX LO in Hz") ("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)") ("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)") ("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz") ("nsamps", po::value<size_t>(&nsamps)->default_value(default_num_samps), "Samples per data capture") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); //print the help message if (vm.count("help")){ std::cout << boost::format("USRP Generate RX IQ Balance Calibration Table %s") % desc << std::endl; std::cout << "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n" << std::endl; return ~0; } //create a usrp device std::cout << std::endl; 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); //set the antennas to cal if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate."); } usrp->set_rx_antenna("CAL"); usrp->set_tx_antenna("CAL"); //set optimum defaults set_optimum_defaults(usrp); //create a receive streamer uhd::stream_args_t stream_args("fc32"); //complex floats uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); //create a transmitter thread boost::thread_group threads; threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_ampl)); //re-usable buffer for samples std::vector<samp_type> buff; //store the results here std::vector<result_t> results; if (not vm.count("freq_start")) freq_start = usrp->get_rx_freq_range().start() + 50e6; if (not vm.count("freq_stop")) freq_stop = usrp->get_rx_freq_range().stop() - 50e6; for (double rx_lo_i = freq_start; rx_lo_i <= freq_stop; rx_lo_i += freq_step){ const double rx_lo = tune_rx_and_tx(usrp, rx_lo_i, tx_offset); //frequency constants for this tune event 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; const double bb_imag_freq = -bb_tone_freq; //capture initial uncorrected value usrp->set_rx_iq_balance(0.0); capture_samples(usrp, rx_stream, buff, nsamps); const double initial_suppression = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate) - compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate); //bounds and results from searching std::complex<double> best_correction; double phase_corr_start = -.3, phase_corr_stop = .3, phase_corr_step; double ampl_corr_start = -.3, ampl_corr_stop = .3, ampl_corr_step; double best_suppression = 0, best_phase_corr = 0, best_ampl_corr = 0; for (size_t i = 0; i < num_search_iters; i++){ phase_corr_step = (phase_corr_stop - phase_corr_start)/(num_search_steps-1); ampl_corr_step = (ampl_corr_stop - ampl_corr_start)/(num_search_steps-1); for (double phase_corr = phase_corr_start; phase_corr <= phase_corr_stop + phase_corr_step/2; phase_corr += phase_corr_step){ for (double ampl_corr = ampl_corr_start; ampl_corr <= ampl_corr_stop + ampl_corr_step/2; ampl_corr += ampl_corr_step){ const std::complex<double> correction(ampl_corr, phase_corr); usrp->set_rx_iq_balance(correction); //receive some samples capture_samples(usrp, rx_stream, buff, nsamps); const double tone_dbrms = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate); const double imag_dbrms = compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate); const double suppression = tone_dbrms - imag_dbrms; if (suppression > best_suppression){ best_correction = correction; best_suppression = suppression; best_phase_corr = phase_corr; best_ampl_corr = ampl_corr; } }} //std::cout << "best_phase_corr " << best_phase_corr << std::endl; //std::cout << "best_ampl_corr " << best_ampl_corr << std::endl; //std::cout << "best_suppression " << best_suppression << std::endl; phase_corr_start = best_phase_corr - phase_corr_step; phase_corr_stop = best_phase_corr + phase_corr_step; ampl_corr_start = best_ampl_corr - ampl_corr_step; ampl_corr_stop = best_ampl_corr + ampl_corr_step; } if (best_suppression > 30){ //most likely valid, keep result result_t result; result.freq = rx_lo; result.real_corr = best_correction.real(); result.imag_corr = best_correction.imag(); result.best = best_suppression; result.delta = best_suppression - initial_suppression; results.push_back(result); if (vm.count("verbose")){ std::cout << boost::format("RX IQ: %f MHz: best suppression %f dB, corrected %f dB") % (rx_lo/1e6) % result.best % result.delta << std::endl; } else std::cout << "." << std::flush; } } std::cout << std::endl; //stop the transmitter threads.interrupt_all(); threads.join_all(); store_results(usrp, results, "RX", "rx", "iq"); return 0; }
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; } } }