git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5481 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
USRP_OBJ += $(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/usrp_lib.o
|
||||
USRP_FILE_OBJ += $(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
|
||||
USRP_CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
|
||||
/** usrp_lib.cpp
|
||||
*
|
||||
* Author: HongliangXU : hong-liang-xu@agilent.com
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <uhd/utils/thread_priority.hpp>
|
||||
#include <uhd/usrp/multi_usrp.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <iostream>
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include "usrp_lib.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
// --------------------------------
|
||||
// variables for USRP configuration
|
||||
// --------------------------------
|
||||
uhd::usrp::multi_usrp::sptr usrp;
|
||||
//uhd::usrp::multi_usrp::sptr rx_usrp;
|
||||
|
||||
//create a send streamer and a receive streamer
|
||||
uhd::tx_streamer::sptr tx_stream;
|
||||
uhd::rx_streamer::sptr rx_stream;
|
||||
|
||||
uhd::tx_metadata_t tx_md;
|
||||
uhd::rx_metadata_t rx_md;
|
||||
|
||||
uhd::time_spec_t tm_spec;
|
||||
//setup variables and allocate buffer
|
||||
uhd::async_metadata_t async_md;
|
||||
|
||||
double sample_rate;
|
||||
// time offset between transmiter timestamp and receiver timestamp;
|
||||
double tdiff;
|
||||
// use usrp_time_offset to get this value
|
||||
int tx_forward_nsamps; //166 for 20Mhz
|
||||
|
||||
|
||||
// --------------------------------
|
||||
// Debug and output control
|
||||
// --------------------------------
|
||||
int num_underflows;
|
||||
int num_overflows;
|
||||
int num_seq_errors;
|
||||
|
||||
int64_t tx_count;
|
||||
int64_t rx_count;
|
||||
openair0_timestamp rx_timestamp;
|
||||
|
||||
} usrp_state_t;
|
||||
|
||||
|
||||
static int trx_usrp_start(openair0_device *device)
|
||||
{
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
// init recv and send streaming
|
||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
|
||||
cmd.time_spec = s->usrp->get_time_now() + uhd::time_spec_t(0.01);
|
||||
cmd.stream_now = false; // start at constant delay
|
||||
s->rx_stream->issue_stream_cmd(cmd);
|
||||
|
||||
s->tx_md.time_spec = s->usrp->get_time_now() + uhd::time_spec_t(1-(double)s->tx_forward_nsamps/s->sample_rate);
|
||||
s->tx_md.has_time_spec = true;
|
||||
s->tx_md.start_of_burst = true;
|
||||
s->tx_md.end_of_burst = false;
|
||||
|
||||
|
||||
s->rx_count = 0;
|
||||
s->tx_count = 0;
|
||||
s->rx_timestamp = 0;
|
||||
}
|
||||
|
||||
static void trx_usrp_end(openair0_device *device)
|
||||
{
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
|
||||
|
||||
//send a mini EOB packet
|
||||
s->tx_md.end_of_burst = true;
|
||||
s->tx_stream->send("", 0, s->tx_md);
|
||||
s->tx_md.end_of_burst = false;
|
||||
}
|
||||
static void trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, const void *buff, int nsamps, int flags)
|
||||
{
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
|
||||
if(flags)
|
||||
s->tx_md.has_time_spec = true;
|
||||
else
|
||||
s->tx_md.has_time_spec = false;
|
||||
s->tx_stream->send(buff, nsamps, s->tx_md);
|
||||
s->tx_md.start_of_burst = false;
|
||||
}
|
||||
|
||||
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void *buff, int nsamps)
|
||||
{
|
||||
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
int samples_received;
|
||||
//TODO: only one channel is supported now
|
||||
samples_received = s->rx_stream->recv(buff, nsamps, s->rx_md);
|
||||
|
||||
//handle the error code
|
||||
switch(s->rx_md.error_code){
|
||||
case uhd::rx_metadata_t::ERROR_CODE_NONE:
|
||||
break;
|
||||
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
|
||||
printf("[recv] USRP RX OVERFLOW!\n");
|
||||
s->num_overflows++;
|
||||
break;
|
||||
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
|
||||
printf("[recv] USRP RX TIMEOUT!\n");
|
||||
break;
|
||||
default:
|
||||
printf("[recv] Unexpected error on RX, Error code: 0x%x\n",s->rx_md.error_code);
|
||||
break;
|
||||
}
|
||||
s->rx_count += nsamps;
|
||||
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
return samples_received;
|
||||
}
|
||||
|
||||
static bool is_equal(double a, double b)
|
||||
{
|
||||
return std::fabs(a-b) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
usrp_state_t *s = (usrp_state_t*)malloc(sizeof(usrp_state_t));
|
||||
memset(s, 0, sizeof(usrp_state_t));
|
||||
|
||||
// Initialize USRP device
|
||||
std::string args = "";
|
||||
uhd::device_addrs_t device_adds = uhd::device::find(args);
|
||||
if(device_adds.size() == 0)
|
||||
{
|
||||
std::cerr<<"No USRP Device Found. " << std::endl;
|
||||
free(s);
|
||||
return -1;
|
||||
}
|
||||
s->usrp = uhd::usrp::multi_usrp::make(args);
|
||||
|
||||
// lock mboard clocks
|
||||
s->usrp->set_clock_source("internal");
|
||||
// set master clock rate and sample rate for tx & rx for streaming
|
||||
s->usrp->set_master_clock_rate(30.72e6);
|
||||
s->usrp->set_rx_rate(openair0_cfg->sample_rate);
|
||||
s->usrp->set_tx_rate(openair0_cfg->sample_rate);
|
||||
|
||||
s->usrp->set_tx_freq(openair0_cfg->tx_freq);
|
||||
s->usrp->set_rx_freq(openair0_cfg->rx_freq);
|
||||
s->usrp->set_tx_gain(openair0_cfg->tx_gain);
|
||||
s->usrp->set_rx_gain(openair0_cfg->rx_gain);
|
||||
s->usrp->set_tx_bandwidth(openair0_cfg->tx_bw);
|
||||
s->usrp->set_rx_bandwidth(openair0_cfg->rx_bw);
|
||||
|
||||
// create tx & rx streamer
|
||||
uhd::stream_args_t stream_args("sc16", "sc16");
|
||||
s->tx_stream = s->usrp->get_tx_stream(stream_args);
|
||||
s->rx_stream = s->usrp->get_rx_stream(stream_args);
|
||||
|
||||
s->usrp->set_time_now(uhd::time_spec_t(0.0));
|
||||
|
||||
// display USRP settings
|
||||
std::cout << std::endl<<boost::format("Actual TX sample rate: %fMSps...") % (s->usrp->get_tx_rate()/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual RX sample rate: %fMSps...") % (s->usrp->get_rx_rate()/1e6) << std::endl;
|
||||
|
||||
std::cout << boost::format("Actual TX frequency: %fGHz...") % (s->usrp->get_tx_freq()/1e9) << std::endl;
|
||||
std::cout << boost::format("Actual RX frequency: %fGHz...") % (s->usrp->get_rx_freq()/1e9) << std::endl;
|
||||
|
||||
std::cout << boost::format("Actual TX gain: %f...") % (s->usrp->get_tx_gain()) << std::endl;
|
||||
std::cout << boost::format("Actual RX gain: %f...") % (s->usrp->get_rx_gain()) << std::endl;
|
||||
|
||||
std::cout << boost::format("Actual TX bandwidth: %fM...") % (s->usrp->get_tx_bandwidth()/1e6) << std::endl;
|
||||
std::cout << boost::format("Actual RX bandwidth: %fM...") % (s->usrp->get_rx_bandwidth()/1e6) << std::endl;
|
||||
|
||||
std::cout << boost::format("Actual TX antenna: %s...") % (s->usrp->get_tx_antenna()) << std::endl;
|
||||
std::cout << boost::format("Actual RX antenna: %s...") % (s->usrp->get_rx_antenna()) << std::endl;
|
||||
|
||||
std::cout << boost::format("Device timestamp: %f...") % (s->usrp->get_time_now().get_real_secs()) << std::endl;
|
||||
|
||||
device->priv = s;
|
||||
device->trx_start_func = trx_usrp_start;
|
||||
device->trx_end_func = trx_usrp_end;
|
||||
device->trx_read_func = trx_usrp_read;
|
||||
device->trx_write_func = trx_usrp_write;
|
||||
|
||||
s->sample_rate = openair0_cfg->sample_rate;
|
||||
// TODO:
|
||||
// init tx_forward_nsamps based usrp_time_offset ex
|
||||
if(is_equal(s->sample_rate, (double)30.72e6))
|
||||
s->tx_forward_nsamps = 176;
|
||||
if(is_equal(s->sample_rate, (double)15.36e6))
|
||||
s->tx_forward_nsamps = 90;
|
||||
if(is_equal(s->sample_rate, (double)7.68e6))
|
||||
s->tx_forward_nsamps = 50;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/** usrp_lib.h
|
||||
*
|
||||
* Author: HongliangXU : hong-liang-xu@agilent.com
|
||||
*/
|
||||
#ifndef USRP_LIB_H
|
||||
#define USRP_LIB_H
|
||||
|
||||
typedef int64_t openair0_timestamp;
|
||||
typedef struct openair0_device_t openair0_device;
|
||||
/* structrue holds the parameters to configure USRP devices
|
||||
*/
|
||||
typedef struct {
|
||||
/* the sample rate for both transmit and receive. */
|
||||
double sample_rate;
|
||||
/* number of RX channels (=RX antennas) */
|
||||
int rx_num_channels;
|
||||
/* number of TX channels (=TX antennas) */
|
||||
int tx_num_channels;
|
||||
/* center frequency in Hz for RX */
|
||||
double rx_freq;
|
||||
/* center frequency in Hz for TX */
|
||||
double tx_freq;
|
||||
/* gain for RX in dB */
|
||||
double rx_gain;
|
||||
/* gain for TX in dB */
|
||||
double tx_gain;
|
||||
/* RX bandwidth in Hz */
|
||||
double rx_bw;
|
||||
/* TX bandwidth in Hz */
|
||||
double tx_bw;
|
||||
} openair0_config_t;
|
||||
|
||||
struct openair0_device_t {
|
||||
/* USRP RF frontend parameters set by application */
|
||||
openair0_config_t openair0_cfg;
|
||||
|
||||
/* Can be used by driver to hold internal structure*/
|
||||
void *priv;
|
||||
|
||||
/* Functions API, which are called by the application*/
|
||||
|
||||
/* Called to start the transceiver. Return 0 if OK, < 0 if error */
|
||||
int (*trx_start_func)(openair0_device *device);
|
||||
|
||||
/* Write 'nsamps' samples on each channel from buffers. buff[0] is the array for
|
||||
* the first channel. timestamp if the time (in samples) at which the first sample
|
||||
* MUST be sent
|
||||
* use flags = 1 to send as timestamp specfied*/
|
||||
void (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, const void *buff, int nsamps, int flags);
|
||||
|
||||
/* Read 'nsamps' samples from each channel to buffers. buff[0] is the array for
|
||||
* the first channel. *ptimestamp is the time at which the first sample
|
||||
* was received.
|
||||
* Return the number of sample read */
|
||||
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void *buff, int nsamps);
|
||||
|
||||
/* Terminate operation of the transceiver -- free all associated resources */
|
||||
void (*trx_end_func)(openair0_device *device);
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
/* return 0 if OK, < 0 if error */
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // USRP_LIB_H
|
||||
Reference in New Issue
Block a user