Exemplo n.º 1
0
/***********************************************************************
 * 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);
}
Exemplo n.º 2
0
/***********************************************************************
 * 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);
}
Exemplo n.º 3
0
 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...);
 }
Exemplo n.º 4
0
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;

}
Exemplo n.º 5
0
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();
}
Exemplo n.º 6
0
/***********************************************************************
 * 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;
        }
    }
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
	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();
}
Exemplo n.º 10
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);
	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;
}
Exemplo n.º 11
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;
}
Exemplo n.º 12
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;




}
Exemplo n.º 13
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);
    }
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
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>(&ampl)->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;
}
Exemplo n.º 17
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;
}
Exemplo n.º 18
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;
}
Exemplo n.º 19
0
/***********************************************************************
 * 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;
}
Exemplo n.º 20
0
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;
}
Exemplo n.º 21
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;
}
Exemplo n.º 22
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;
}
Exemplo n.º 24
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>(&ampl)->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;
}
Exemplo n.º 25
0
int UHD_SAFE_MAIN(int argc, char *argv[]){
    
    uhd::set_thread_priority_safe();    

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

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

    //------------------INIT TX------------------
                                        //Set the scheduling priority on the current thread. Same as set_thread_priority but does not throw on failure.
    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);       //Make the usrp by calling the constructor with param the args

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

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

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



        

    

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

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

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

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

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

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

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

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

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

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

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

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




    //Setup metadata    

    //Setup tx_metadata

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

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

    }else{
        tx_md.has_time_spec = false;
    }

    //Setup rx_metadata
    uhd::rx_metadata_t rx_md;

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




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


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


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

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

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

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

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


    size_t num_rx_samps = 0;

    

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

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


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

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


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



    switch ( rx_md.error_code ) {

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

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

    }    

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



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



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




 
    
    return EXIT_SUCCESS;
}
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;
}
Exemplo n.º 27
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;
}
Exemplo n.º 28
0
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;
}
Exemplo n.º 29
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;
}
Exemplo n.º 30
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;
        }
    }
}