Merge branch 'master' into feature-21-TM7
Conflicts: openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c openair1/SCHED/phy_procedures_lte_ue.c openair1/SIMULATION/LTE_PHY/dlsim.c openair1/SIMULATION/LTE_PHY/mbmssim.c targets/RT/USER/Makefile
This commit is contained in:
@@ -37,24 +37,299 @@
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "bladerf_lib.h"
|
||||
#include "common_lib.h"
|
||||
#include "log.h"
|
||||
|
||||
#define SAMPLE_LEN samples_per_frame*sizeof(int32_t)
|
||||
|
||||
int num_devices=0;
|
||||
/*These items configure the underlying asynch stream used by the the sync interface.
|
||||
*/
|
||||
unsigned int num_buffers;
|
||||
unsigned int buffer_size;
|
||||
unsigned int num_transfers;
|
||||
unsigned int timeout_ms;
|
||||
|
||||
|
||||
int trx_brf_init(openair0_device *openair0) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
openair0_timestamp trx_get_timestamp(openair0_device *device) {
|
||||
int status;
|
||||
struct bladerf_metadata meta;
|
||||
brf_state_t *brf = (brf_state_t*)device->priv;
|
||||
|
||||
if ((status=bladerf_get_timestamp(brf->dev, BLADERF_MODULE_TX, &meta.timestamp)) != 0) {
|
||||
fprintf(stderr,"Failed to get current RX timestamp: %s\n",bladerf_strerror(status));
|
||||
} else {
|
||||
printf("Current TX timestampe 0x%016"PRIx64"\n", meta.timestamp);
|
||||
}
|
||||
return meta.timestamp;
|
||||
}
|
||||
|
||||
|
||||
int trx_brf_start(openair0_device *openair0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trx_brf_stats(openair0_device *device){
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int trx_brf_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc) {
|
||||
|
||||
int status, i;
|
||||
brf_state_t *brf = (brf_state_t*)device->priv;
|
||||
/* BRF has only 1 rx/tx chaine : is it correct? */
|
||||
void *samples = (void*)buff[0];
|
||||
|
||||
//brf->meta_tx.flags &= ~BLADERF_META_FLAG_TX_NOW;
|
||||
brf->meta_tx.flags = BLADERF_META_FLAG_TX_BURST_START |
|
||||
BLADERF_META_FLAG_TX_NOW |
|
||||
BLADERF_META_FLAG_TX_BURST_END;
|
||||
|
||||
brf->meta_tx.timestamp= (uint64_t) ptimestamp;
|
||||
|
||||
status = bladerf_sync_tx(brf->dev, samples, (unsigned int) nsamps, &brf->meta_tx, 2*brf->tx_timeout_ms);
|
||||
|
||||
if (status != 0) {
|
||||
fprintf(stderr,"Failed to TX sample: %s\n", bladerf_strerror(status));
|
||||
brf->num_tx_errors++;
|
||||
brf_error(status);
|
||||
} else if (brf->meta_tx.status & BLADERF_META_STATUS_UNDERRUN){
|
||||
/* libbladeRF does not report this status. It is here for future use. */
|
||||
fprintf(stderr, "TX Underrun detected. %u valid samples were read.\n", brf->meta_tx.actual_count);
|
||||
brf->num_underflows++;
|
||||
}
|
||||
// printf("tx status %d \n",brf->meta_tx.status);
|
||||
brf->tx_current_ts=brf->meta_tx.timestamp;
|
||||
brf->tx_actual_nsamps+=brf->meta_tx.actual_count;
|
||||
brf->tx_nsamps+=nsamps;
|
||||
brf->tx_count++;
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int trx_brf_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
|
||||
int status, ret;
|
||||
|
||||
unsigned int i;
|
||||
brf_state_t *brf = (brf_state_t*)device->priv;
|
||||
|
||||
// BRF has only one rx/tx chain
|
||||
void *samples = (void*)buff[0];
|
||||
|
||||
brf->meta_rx.flags |= BLADERF_META_FLAG_RX_NOW;
|
||||
status = bladerf_sync_rx(brf->dev, samples, (unsigned int) nsamps, &brf->meta_rx, 2*brf->rx_timeout_ms);
|
||||
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "RX failed: %s\n", bladerf_strerror(status));
|
||||
brf->num_rx_errors++;
|
||||
} else if ( brf->meta_rx.status & BLADERF_META_STATUS_OVERRUN) {
|
||||
brf->num_overflows++;
|
||||
fprintf(stderr, "RX overrun (%d) is detected. t=0x%"PRIu64". Got %u samples. nsymps %d\n",
|
||||
brf->num_overflows,brf->meta_rx.timestamp, brf->meta_rx.actual_count, nsamps);
|
||||
//brf->meta_rx.timestamp=(unsigned int)(nsamps-brf->meta_rx.actual_count);
|
||||
}
|
||||
//printf("[BRF] (buff %p) ts=0x%"PRIu64" %s\n",samples, brf->meta_rx.timestamp,bladerf_strerror(status));
|
||||
brf->rx_current_ts=brf->meta_rx.timestamp;
|
||||
brf->rx_actual_nsamps+=brf->meta_rx.actual_count;
|
||||
brf->rx_nsamps+=nsamps;
|
||||
brf->rx_count++;
|
||||
|
||||
|
||||
*ptimestamp = brf->meta_rx.timestamp;
|
||||
|
||||
return brf->meta_rx.actual_count;
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_end(openair0_device *device) {
|
||||
|
||||
int status;
|
||||
brf_state_t *brf = (brf_state_t*)device->priv;
|
||||
// Disable RX module, shutting down our underlying RX stream
|
||||
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_RX, false)) != 0) {
|
||||
fprintf(stderr, "Failed to disable RX module: %s\n", bladerf_strerror(status));
|
||||
}
|
||||
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_TX, false)) != 0) {
|
||||
fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status));
|
||||
}
|
||||
bladerf_close(brf->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int trx_brf_get_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_stop(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_set_freq(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int trx_brf_set_gains(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
int status;
|
||||
int card=0;
|
||||
|
||||
brf_state_t *brf = (brf_state_t*)malloc(sizeof(brf_state_t));
|
||||
memset(brf, 0, sizeof(brf_state_t));
|
||||
// init required params for BRF
|
||||
brf->num_buffers = 128;
|
||||
brf->buffer_size = (unsigned int) openair0_cfg[card].samples_per_packet*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
|
||||
brf->num_transfers = 16;
|
||||
brf->rx_timeout_ms = 0;
|
||||
brf->tx_timeout_ms = 0;
|
||||
brf->sample_rate=(unsigned int)openair0_cfg[card].sample_rate;
|
||||
|
||||
|
||||
printf("\n[BRF] sampling_rate %d, num_buffers %d, buffer_size %d, num transfer %d, timeout_ms (rx %d, tx %d)\n",
|
||||
brf->sample_rate, brf->num_buffers, brf->buffer_size,brf->num_transfers, brf->rx_timeout_ms, brf->tx_timeout_ms);
|
||||
|
||||
if ((status=bladerf_open(&brf->dev, "")) != 0 ) {
|
||||
fprintf(stderr,"Failed to open brf device: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
printf("[BRF] init dev %p\n", brf->dev);
|
||||
switch(bladerf_device_speed(brf->dev)){
|
||||
case BLADERF_DEVICE_SPEED_SUPER:
|
||||
printf("[BRF] Device operates at max speed\n");
|
||||
break;
|
||||
default:
|
||||
printf("[BRF] Device does not operates at max speed, change the USB port\n");
|
||||
brf_error(BLADERF_ERR_UNSUPPORTED);
|
||||
}
|
||||
// RX
|
||||
// Example of CLI output: RX Frequency: 2539999999Hz
|
||||
|
||||
if ((status=bladerf_set_frequency(brf->dev, BLADERF_MODULE_RX, (unsigned int) openair0_cfg[card].rx_freq[0])) != 0){
|
||||
fprintf(stderr,"Failed to set RX frequency: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
} else
|
||||
printf("[BRF] set RX frequency to %f\n",openair0_cfg[card].rx_freq[0]);
|
||||
|
||||
|
||||
if ((status=bladerf_set_sample_rate(brf->dev, BLADERF_MODULE_RX, (unsigned int)openair0_cfg[card].sample_rate, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set RX sample rate: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set RX sample rate to %f\n",openair0_cfg[card].sample_rate);
|
||||
|
||||
if ((status=bladerf_set_bandwidth(brf->dev, BLADERF_MODULE_RX, (unsigned int) openair0_cfg[card].rx_bw, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set RX bandwidth: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set RX bandwidth to %f\n",openair0_cfg[card].rx_bw);
|
||||
|
||||
if ((status=bladerf_set_gain(brf->dev, BLADERF_MODULE_RX, (int) openair0_cfg[card].rx_gain[0])) != 0) {
|
||||
fprintf(stderr,"Failed to set RX gain: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
} else
|
||||
printf("[BRF] set RX gain to %f\n",openair0_cfg[card].rx_gain[0]);
|
||||
|
||||
/* Configure the device's RX module for use with the sync interface.
|
||||
* SC16 Q11 samples *with* metadata are used. */
|
||||
if ((status=bladerf_sync_config(brf->dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11_META,brf->num_buffers,brf->buffer_size,brf->num_transfers,brf->rx_timeout_ms)) != 0 ) {
|
||||
fprintf(stderr,"Failed to configure RX sync interface: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] configured Rx for sync interface \n");
|
||||
|
||||
/* We must always enable the RX module after calling bladerf_sync_config(), and
|
||||
* before attempting to RX samples via bladerf_sync_rx(). */
|
||||
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_RX, true)) != 0) {
|
||||
fprintf(stderr,"Failed to enable RX module: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] RX module enabled \n");
|
||||
|
||||
// TX
|
||||
if ((status=bladerf_set_frequency(brf->dev, BLADERF_MODULE_TX, (unsigned int) openair0_cfg[card].tx_freq[0])) != 0){
|
||||
fprintf(stderr,"Failed to set TX frequency: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set Tx Frequenct to %f \n", openair0_cfg[card].tx_freq[0]);
|
||||
|
||||
if ((status=bladerf_set_sample_rate(brf->dev, BLADERF_MODULE_TX, (unsigned int) openair0_cfg[card].sample_rate, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set TX sample rate: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set Tx sampling rate to %f \n", openair0_cfg[card].sample_rate);
|
||||
|
||||
if ((status=bladerf_set_bandwidth(brf->dev, BLADERF_MODULE_TX,(unsigned int)openair0_cfg[card].tx_bw, NULL)) != 0){
|
||||
fprintf(stderr, "Failed to set RX bandwidth: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set Tx sampling ratebandwidth to %f \n", openair0_cfg[card].tx_bw);
|
||||
|
||||
if ((status=bladerf_set_gain(brf->dev, BLADERF_MODULE_TX, (int)openair0_cfg[card].tx_gain[0])) != 0) {
|
||||
fprintf(stderr,"Failed to set TX gain: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] set the Tx gain to %f \n", openair0_cfg[card].tx_gain[0]);
|
||||
|
||||
|
||||
/* Configure the device's TX module for use with the sync interface.
|
||||
* SC16 Q11 samples *with* metadata are used. */
|
||||
if ((status=bladerf_sync_config(brf->dev, BLADERF_MODULE_TX,BLADERF_FORMAT_SC16_Q11_META,brf->num_buffers,brf->buffer_size,brf->num_transfers,brf->tx_timeout_ms)) != 0 ) {
|
||||
fprintf(stderr,"Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}else
|
||||
printf("[BRF] configured tx for sync interface \n");
|
||||
|
||||
/* We must always enable the TX module after calling bladerf_sync_config(), and
|
||||
* before attempting to TX samples via bladerf_sync_tx(). */
|
||||
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_TX, true)) != 0) {
|
||||
fprintf(stderr,"Failed to enable TX module: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
} else
|
||||
printf("[BRF] TX module enabled \n");
|
||||
|
||||
bladerf_log_set_verbosity(get_brf_log_level(openair0_cfg[card].log_level));
|
||||
|
||||
printf("BLADERF: Initializing openair0_device\n");
|
||||
device->priv = brf;
|
||||
device->Mod_id = num_devices++;
|
||||
device->trx_start_func = trx_brf_start;
|
||||
device->trx_end_func = trx_brf_end;
|
||||
device->trx_read_func = trx_brf_read;
|
||||
device->trx_write_func = trx_brf_write;
|
||||
device->trx_get_stats_func = trx_brf_get_stats;
|
||||
device->trx_reset_stats_func = trx_brf_reset_stats;
|
||||
device->trx_stop_func = trx_brf_stop;
|
||||
device->trx_set_freq_func = trx_brf_set_freq;
|
||||
device->trx_set_gains_func = trx_brf_set_gains;
|
||||
memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brf_error(int status) {
|
||||
|
||||
//exit(-1);
|
||||
//return 1; // or status error code
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct bladerf * open_bladerf_from_serial(const char *serial) {
|
||||
|
||||
int status;
|
||||
@@ -81,218 +356,10 @@ struct bladerf * open_bladerf_from_serial(const char *serial) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int trx_brf_start(openair0_device *openair0) {
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc) {
|
||||
int status;
|
||||
struct bladerf_metadata meta;
|
||||
int16_t zeros[] = { 0, 0, 0, 0 };
|
||||
struct bladerf *dev = (struct bladerf*) device->priv;
|
||||
openair0_timestamp current_timestamp;
|
||||
/* BRF has only 1 rx/tx chaine : is it correct? */
|
||||
void *sample = (void*)buff[0];
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
|
||||
/* Retrieve the current timestamp */
|
||||
#ifdef BRF_TEST
|
||||
if ((status=bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp)) != 0) {
|
||||
fprintf(stderr,"Failed to get current RX timestamp: %s\n",bladerf_strerror(status));
|
||||
} else {
|
||||
current_timestamp = meta.timestamp;
|
||||
printf("Current TX timestampe 0x%016"PRIx64" and current timestamp: 0x%016"PRIx64"\n", ptimestamp, meta.timestamp);
|
||||
}
|
||||
#endif
|
||||
meta.timestamp= ptimestamp;
|
||||
|
||||
meta.flags |= BLADERF_META_FLAG_TX_NOW;
|
||||
|
||||
status = bladerf_sync_tx(dev, sample, nsamps, &meta, timeout_ms);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "Failed to TX sample: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
|
||||
int status, ret;
|
||||
struct bladerf_metadata meta;
|
||||
unsigned int i;
|
||||
struct bladerf *dev = (struct bladerf*) device->priv;
|
||||
/* BRF has only onerx/tx chain: is it correct? */
|
||||
void *sample = (void*)buff[0];
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
/* Retrieve the current timestamp */
|
||||
if ((status=bladerf_get_timestamp(dev, BLADERF_MODULE_RX, &meta.timestamp)) != 0) {
|
||||
fprintf(stderr,"Failed to get current RX timestamp: %s\n",bladerf_strerror(status));
|
||||
} else {
|
||||
*ptimestamp = meta.timestamp;
|
||||
printf("Current RX timestamp: 0x%016"PRIx64"\n", meta.timestamp);
|
||||
}
|
||||
|
||||
meta.flags |= BLADERF_META_FLAG_RX_NOW;
|
||||
//fflush(stdout);
|
||||
|
||||
status = bladerf_sync_rx(dev, sample, nsamps, &meta, timeout_ms);
|
||||
|
||||
/* if (meta.actual_count < nsamps ) {
|
||||
printf("[BRF][RX] received %d samples out of %d\n", meta.actual_count, nsamps);
|
||||
}
|
||||
*/
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "RX failed: %s\n", bladerf_strerror(status));
|
||||
} else if (meta.status & BLADERF_META_STATUS_OVERRUN) {
|
||||
fprintf(stderr, "Overrun detected in RX. %u valid samples were read (nsymps %d)\n", meta.actual_count,nsamps);
|
||||
} else if (meta.status & BLADERF_META_STATUS_UNDERRUN) {
|
||||
fprintf(stderr, "Underrun detected in RX. %u valid samples were read (nsymps %d) \n", meta.actual_count,nsamps);
|
||||
}else {
|
||||
printf("Got %u samples at t=0x%016"PRIx64"\n", meta.actual_count, meta.timestamp);
|
||||
}
|
||||
|
||||
return meta.actual_count;
|
||||
|
||||
}
|
||||
|
||||
int trx_brf_end(openair0_device *device) {
|
||||
|
||||
int status;
|
||||
struct bladerf *dev = (struct bladerf*) device->priv;
|
||||
// Disable RX module, shutting down our underlying RX stream
|
||||
if ((status=bladerf_enable_module(device->priv, BLADERF_MODULE_RX, false)) != 0) {
|
||||
fprintf(stderr, "Failed to disable RX module: %s\n", bladerf_strerror(status));
|
||||
}
|
||||
if ((status=bladerf_enable_module(device->priv, BLADERF_MODULE_TX, false)) != 0) {
|
||||
fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status));
|
||||
}
|
||||
bladerf_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int openair0_device_brf_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
int status;
|
||||
int card=0;
|
||||
//struct bladerf_version *version;
|
||||
//printf("Opening the brf device (version %s)...\n", bladerf_version(version));
|
||||
|
||||
// opaque data struct
|
||||
struct bladerf *dev;// = (struct bladerf*)malloc(sizeof(struct bladerf));
|
||||
//memset(dev, 0, sizeof(struct bladerf));
|
||||
// An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
|
||||
|
||||
// init required params for BRF
|
||||
num_buffers = 16;
|
||||
buffer_size = openair0_cfg[card]. samples_per_packet*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
|
||||
num_transfers = 8; // ? device->openair0_cfg.samples_per_packets
|
||||
timeout_ms = 1; // or 0/
|
||||
|
||||
printf("the buffer_size is set to %d\n", buffer_size);
|
||||
|
||||
if ((status=bladerf_open(&dev, "")) != 0 ) {
|
||||
fprintf(stderr,"Failed to open brf device: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
printf("[BRF] device speed is %d\n",bladerf_device_speed(dev) );
|
||||
|
||||
// RX
|
||||
// Example of CLI output: RX Frequency: 2539999999Hz
|
||||
|
||||
if ((status=bladerf_set_frequency(dev, BLADERF_MODULE_RX, openair0_cfg[card].rx_freq[0])) != 0){
|
||||
fprintf(stderr,"Failed to set RX frequency: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
// RX sample rate: 7680000 0/1
|
||||
if ((status=bladerf_set_sample_rate(dev, BLADERF_MODULE_RX, openair0_cfg[card].sample_rate, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set RX sample rate: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
// RX Bandwidth: 14000000Hz
|
||||
if ((status=bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, openair0_cfg[card].rx_bw, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set RX bandwidth: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
// desired gain = 16
|
||||
if ((status=bladerf_set_gain(dev, BLADERF_MODULE_RX, openair0_cfg[card].rx_gain[0])) != 0) {
|
||||
fprintf(stderr,"Failed to set RX gain: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
/* Configure the device's RX module for use with the sync interface.
|
||||
* SC16 Q11 samples *with* metadata are used. */
|
||||
if ((status=bladerf_sync_config(dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11_META,num_buffers,buffer_size,num_transfers,timeout_ms)) != 0 ) {
|
||||
fprintf(stderr,"Failed to configure RX sync interface: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
/* We must always enable the RX module after calling bladerf_sync_config(), and
|
||||
* before attempting to RX samples via bladerf_sync_rx(). */
|
||||
if ((status=bladerf_enable_module(dev, BLADERF_MODULE_RX, true)) != 0) {
|
||||
fprintf(stderr,"Failed to enable RX module: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
// TX
|
||||
if ((status=bladerf_set_frequency(dev, BLADERF_MODULE_TX, openair0_cfg[card].tx_freq[0])) != 0){
|
||||
fprintf(stderr,"Failed to set TX frequency: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
if ((status=bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, openair0_cfg[card].sample_rate, NULL)) != 0){
|
||||
fprintf(stderr,"Failed to set TX sample rate: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
if ((status=bladerf_set_bandwidth(dev, BLADERF_MODULE_TX,openair0_cfg[card].tx_bw, NULL)) != 0){
|
||||
fprintf(stderr, "Failed to set RX bandwidth: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
if ((status=bladerf_set_gain(dev, BLADERF_MODULE_TX, openair0_cfg[card].tx_gain[0])) != 0) {
|
||||
fprintf(stderr,"Failed to set TX gain: %s\n",bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
/* Configure the device's TX module for use with the sync interface.
|
||||
* SC16 Q11 samples *with* metadata are used. */
|
||||
if ((status=bladerf_sync_config(dev, BLADERF_MODULE_TX,BLADERF_FORMAT_SC16_Q11_META,num_buffers,buffer_size,num_transfers,timeout_ms)) != 0 ) {
|
||||
fprintf(stderr,"Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
/* We must always enable the TX module after calling bladerf_sync_config(), and
|
||||
* before attempting to TX samples via bladerf_sync_tx(). */
|
||||
if ((status=bladerf_enable_module(dev, BLADERF_MODULE_TX, true)) != 0) {
|
||||
fprintf(stderr,"Failed to enable TX module: %s\n", bladerf_strerror(status));
|
||||
brf_error(status);
|
||||
}
|
||||
|
||||
|
||||
bladerf_log_set_verbosity(get_brf_log_level(openair0_cfg[card].log_level));
|
||||
|
||||
printf("BLADERF: Initializing openair0_device\n");
|
||||
device->priv = dev;
|
||||
device->Mod_id = num_devices++;
|
||||
device->trx_start_func = trx_brf_start;
|
||||
device->trx_end_func = trx_brf_end;
|
||||
device->trx_read_func = trx_brf_read;
|
||||
device->trx_write_func = trx_brf_write;
|
||||
memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
|
||||
}
|
||||
|
||||
void brf_error(int status) {
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int get_brf_log_level(int log_level){
|
||||
|
||||
int level=BLADERF_LOG_LEVEL_INFO;
|
||||
//return BLADERF_LOG_LEVEL_DEBUG;
|
||||
switch(log_level) {
|
||||
case LOG_DEBUG:
|
||||
level=BLADERF_LOG_LEVEL_DEBUG;
|
||||
|
||||
@@ -33,46 +33,54 @@
|
||||
*/
|
||||
|
||||
#include <libbladeRF.h>
|
||||
/*
|
||||
enum brf_err_num{
|
||||
BLADERF_ERR_MIN=0,
|
||||
BLADERF_ERR_UNEXPECTED=-1,
|
||||
BLADERF_ERR_RANGE=-2,
|
||||
BLADERF_ERR_INVAL=-3,
|
||||
BLADERF_ERR_MEM=-4,
|
||||
BLADERF_ERR_IO=-5,
|
||||
BLADERF_ERR_TIMEOUT=-6,
|
||||
BLADERF_ERR_NODEV=-7,
|
||||
BLADERF_ERR_UNSUPPORTED=-8,
|
||||
BLADERF_ERR_MISALIGNED=-9,
|
||||
BLADERF_ERR_CHECKSUM=-10,
|
||||
BLADERF_ERR_NO_FILE=-11,
|
||||
BLADERF_ERR_UPDATE_FPGA=-12,
|
||||
BLADERF_ERR_UPDATE_FW=-13,
|
||||
BLADERF_ERR_TIME_PAST=-14,
|
||||
BLADERF_ERR_MAX=-15,
|
||||
}
|
||||
mapping brf_err_names[] = {
|
||||
{"BLADERF_OK", BLADERF_ERR_MIN},
|
||||
{"BLADERF_ERR_UNEXPECTED",BLADERF_ERR_UNEXPECTED},
|
||||
{"BLADERF_ERR_RANGE",BLADERF_ERR_RANGE},
|
||||
{"BLADERF_ERR_INVAL",BLADERF_ERR_INVAL},
|
||||
{"BLADERF_ERR_MEM",BLADERF_ERR_MEM},
|
||||
{"BLADERF_ERR_IO",BLADERF_ERR_IO},
|
||||
{"BLADERF_ERR_TIMEOUT",BLADERF_ERR_TIMEOUT},
|
||||
{"BLADERF_ERR_NODEV",BLADERF_ERR_NODEV},
|
||||
{"BLADERF_ERR_UNSUPPORTED",BLADERF_ERR_UNSUPPORTED},
|
||||
{"BLADERF_ERR_MISALIGNED",BLADERF_ERR_MISALIGNED},
|
||||
{"BLADERF_ERR_CHECKSUM",BLADERF_ERR_CHECKSUM},
|
||||
{"BLADERF_ERR_NO_FILE",BLADERF_ERR_NO_FILE},
|
||||
{"BLADERF_ERR_UPDATE_FPGA",BLADERF_ERR_UPDATE_FPGA},
|
||||
{"BLADERF_ERR_UPDATE_FW",BLADERF_ERR_UPDATE_FW},
|
||||
{"BLADERF_ERR_TIME_PAST",BLADERF_ERR_TIME_PAST},
|
||||
{NULL, BLADERF_ERR_MAX}
|
||||
};
|
||||
*/
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "log.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
// opaque BRF data struct
|
||||
struct bladerf *dev;
|
||||
// An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
|
||||
|
||||
unsigned int num_buffers;
|
||||
unsigned int buffer_size;
|
||||
unsigned int num_transfers;
|
||||
unsigned int rx_timeout_ms;
|
||||
unsigned int tx_timeout_ms;
|
||||
|
||||
struct bladerf_metadata meta_rx;
|
||||
struct bladerf_metadata meta_tx;
|
||||
|
||||
unsigned int sample_rate;
|
||||
// time offset between transmiter timestamp and receiver timestamp;
|
||||
double tdiff;
|
||||
// use brf_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;
|
||||
int num_rx_errors;
|
||||
int num_tx_errors;
|
||||
|
||||
uint64_t tx_current_ts;
|
||||
uint64_t rx_current_ts;
|
||||
uint64_t tx_actual_nsamps;
|
||||
uint64_t rx_actual_nsamps;
|
||||
uint64_t tx_nsamps;
|
||||
uint64_t rx_nsamps;
|
||||
uint64_t tx_count;
|
||||
uint64_t rx_count;
|
||||
openair0_timestamp rx_timestamp;
|
||||
|
||||
} brf_state_t;
|
||||
/*
|
||||
* func prototypes
|
||||
*/
|
||||
|
||||
void brf_error(int status);
|
||||
int brf_error(int status);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/*! \file common_lib.c
|
||||
* \brief common APIs for different RF frontend device
|
||||
* \author HongliangXU, Navid Nikaein
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "common_lib.h"
|
||||
|
||||
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
#ifdef ETHERNET
|
||||
device->type=ETH_IF;
|
||||
device->func_type = BBU_FUNC;
|
||||
openair0_dev_init_eth(device, openair0_cfg);
|
||||
printf(" openair0_dev_init_eth ...\n");
|
||||
#elif EXMIMO
|
||||
device->type=EXMIMO_IF;
|
||||
openair0_dev_init_exmimo(device, openair0_cfg);
|
||||
printf("openair0_dev_init_exmimo...\n");
|
||||
#elif OAI_USRP
|
||||
device->type=USRP_IF;
|
||||
openair0_dev_init_usrp(device, openair0_cfg);
|
||||
printf("openair0_dev_init_usrp ...\n");
|
||||
#elif OAI_BLADERF
|
||||
device->type=BLADERF_IF;
|
||||
openair0_dev_init_bladerf(device, openair0_cfg);
|
||||
printf(" openair0_dev_init_bladerf ...\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -26,40 +26,68 @@
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/*! \file common_lib.h
|
||||
* \brief common APIs for different RF frontend device
|
||||
* \author HongliangXU, Navid Nikaein
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
/** common_lib.h
|
||||
*
|
||||
* Author: HongliangXU : hong-liang-xu@agilent.com
|
||||
*/
|
||||
#ifndef COMMON_LIB_H
|
||||
#define COMMON_LIB_H
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef int64_t openair0_timestamp;
|
||||
typedef volatile int64_t openair0_vtimestamp;
|
||||
|
||||
|
||||
/* structrue holds the parameters to configure USRP devices*/
|
||||
typedef struct openair0_device_t openair0_device;
|
||||
/* structrue holds the parameters to configure USRP devices
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXMIMO
|
||||
#define MAX_CARDS 1
|
||||
#endif
|
||||
|
||||
#define USRP_GAIN_OFFSET (86.0) // 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output
|
||||
//#define USRP_GAIN_OFFSET (56.0) // 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output
|
||||
|
||||
typedef enum {
|
||||
max_gain=0,med_gain,byp_gain
|
||||
} rx_gain_t;
|
||||
|
||||
/** @addtogroup _PHY_RF_INTERFACE_
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
//! Frequency for which RX chain was calibrated
|
||||
double freq;
|
||||
//! Offset to be applied to RX gain
|
||||
double offset;
|
||||
} rx_gain_calib_table_t;
|
||||
|
||||
typedef struct {
|
||||
//! Module ID for this configuration
|
||||
int Mod_id;
|
||||
// device log level
|
||||
int log_level;
|
||||
//! number of downlink resource blocks
|
||||
int num_rb_dl;
|
||||
//! number of samples per frame
|
||||
unsigned int samples_per_frame;
|
||||
//! the sample rate for both transmit and receive.
|
||||
double sample_rate;
|
||||
//! number of samples per RX/TX packet (USRP + Ethernet)
|
||||
int samples_per_packet;
|
||||
// delay in sending samples (write) due to hardware access, softmodem processing and fronthaul delay if exist
|
||||
int tx_delay;
|
||||
//! adjust the position of the samples after delay when sending
|
||||
unsigned int tx_forward_nsamps;
|
||||
//! number of RX channels (=RX antennas)
|
||||
int rx_num_channels;
|
||||
//! number of TX channels (=TX antennas)
|
||||
@@ -70,21 +98,31 @@ typedef struct {
|
||||
//! \brief Center frequency in Hz for TX.
|
||||
//! index: [0..rx_num_channels[ !!! see lte-ue.c:427 FIXME iterates over rx_num_channels
|
||||
double tx_freq[4];
|
||||
//! mode for rxgain (ExpressMIMO2)
|
||||
//! mode for rxgain (ExpressMIMO2)
|
||||
rx_gain_t rxg_mode[4];
|
||||
//! \brief Gain for RX in dB.
|
||||
//! index: [0..rx_num_channels]
|
||||
double rx_gain[4];
|
||||
//! \brief Gain offset (for calibration) in dB
|
||||
//! index: [0..rx_num_channels]
|
||||
double rx_gain_offset[4];
|
||||
//! gain for TX in dB
|
||||
double tx_gain[4];
|
||||
//! RX bandwidth in Hz
|
||||
double rx_bw;
|
||||
//! TX bandwidth in Hz
|
||||
double tx_bw;
|
||||
//! Auto calibration flag
|
||||
int autocal[4];
|
||||
//! RRH IP addr for Ethernet interface
|
||||
char *rrh_ip;
|
||||
char *remote_ip;
|
||||
//! RRH port number for Ethernet interface
|
||||
int rrh_port;
|
||||
int remote_port;
|
||||
//! my IP addr for Ethernet interface (eNB/BBU, UE)
|
||||
char *my_ip;
|
||||
//! my port number for Ethernet interface (eNB/BBU, UE)
|
||||
int my_port;
|
||||
|
||||
} openair0_config_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -96,9 +134,50 @@ typedef struct {
|
||||
|
||||
|
||||
|
||||
/*!\brief interface types that apply to modules (RRH_BBU/RRH_UE) created in RRH (rrh_gw.c)
|
||||
and are defined with respect to the RF device that is present in RRH
|
||||
-RRH_BBU modules have two devices, one is by default ETHERNET (will have ETH_IF) and the other one is a
|
||||
RF device (EXMIMO,USRP,BLADERF) or no device (NONE_IF).
|
||||
-RRH_UE modules have two devices one is by default ETHERNET (will have ETH_IF)
|
||||
and the other one by default not present so it will have NONE_IF
|
||||
*/
|
||||
typedef enum {
|
||||
MIN_DEV_TYPE = 0,
|
||||
/*!\brief device is ETH */
|
||||
ETH_IF,
|
||||
/*!\brief device is ExpressMIMO */
|
||||
EXMIMO_IF,
|
||||
/*!\brief device is USRP*/
|
||||
USRP_IF,
|
||||
/*!\brief device is BLADE RF*/
|
||||
BLADERF_IF,
|
||||
/*!\brief device is NONE*/
|
||||
NONE_IF,
|
||||
MAX_DEV_TYPE
|
||||
|
||||
} dev_type_t;
|
||||
|
||||
|
||||
/*!\brief openair0 device host type */
|
||||
typedef enum {
|
||||
MIN_FUNC_TYPE = 0,
|
||||
/*!\brief device functions within a BBU */
|
||||
BBU_FUNC,
|
||||
/*!\brief device functions within a RRH */
|
||||
RRH_FUNC,
|
||||
MAX_FUNC_TYPE
|
||||
|
||||
}func_type_t;
|
||||
|
||||
struct openair0_device_t {
|
||||
/* Module ID of this device */
|
||||
int Mod_id;
|
||||
|
||||
/* Type of this device */
|
||||
dev_type_t type;
|
||||
|
||||
/* Type of the device's host (BBU/RRH) */
|
||||
func_type_t func_type;
|
||||
|
||||
/* RF frontend parameters set by application */
|
||||
openair0_config_t openair0_cfg;
|
||||
@@ -108,14 +187,34 @@ struct openair0_device_t {
|
||||
|
||||
/* Functions API, which are called by the application*/
|
||||
|
||||
/* Called to start the transceiver. Return 0 if OK, < 0 if error */
|
||||
/*! \brief Called to start the transceiver. Return 0 if OK, < 0 if error
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
*/
|
||||
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, void **buff, int nsamps, int cc, int flags);
|
||||
/*! \brief Called to send a request message between BBU-RRH
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param msg pointer to the message structure passed between BBU-RRH
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
int (*trx_request_func)(openair0_device *device, void *msg, ssize_t msg_len);
|
||||
|
||||
/*! \brief Called to send a reply message between BBU-RRH
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param msg pointer to the message structure passed between BBU-RRH
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
int (*trx_reply_func)(openair0_device *openair0, void *msg, ssize_t msg_len);
|
||||
|
||||
/*! \brief Called to send samples to the RF target
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param timestamp The timestamp at whicch the first sample MUST be sent
|
||||
@param buff Buffer which holds the samples
|
||||
@param nsamps number of samples to be sent
|
||||
@param antenna_id index of the antenna if the device has multiple anteannas
|
||||
@param flags flags must be set to TRUE if timestamp parameter needs to be applied
|
||||
*/
|
||||
int (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags);
|
||||
|
||||
/*! \brief Receive samples from hardware.
|
||||
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
|
||||
@@ -128,10 +227,40 @@ struct openair0_device_t {
|
||||
* \param cc Number of channels. If cc == 1, only buff[0] is filled with samples.
|
||||
* \returns the number of sample read
|
||||
*/
|
||||
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int cc);
|
||||
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
|
||||
|
||||
/* Terminate operation of the transceiver -- free all associated resources */
|
||||
/*! \brief print the device statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 on success
|
||||
*/
|
||||
int (*trx_get_stats_func)(openair0_device *device);
|
||||
|
||||
/*! \brief Reset device statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_reset_stats_func)(openair0_device *device);
|
||||
|
||||
/*! \brief Terminate operation of the transceiver -- free all associated resources */
|
||||
void (*trx_end_func)(openair0_device *device);
|
||||
|
||||
/* Terminate operation */
|
||||
int (*trx_stop_func)(int card);
|
||||
|
||||
/* Functions API related to UE*/
|
||||
|
||||
/*! \brief Set RX feaquencies
|
||||
* \param
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_set_freq_func)(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
|
||||
|
||||
/*! \brief Set gains
|
||||
* \param
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_set_gains_func)(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -140,13 +269,22 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* return 0 if OK, < 0 if error */
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
openair0_timestamp get_usrp_time(openair0_device *device);
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
|
||||
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
/*! \brief Initialize Openair RF target. It returns 0 if OK */
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
|
||||
//USRP
|
||||
/*! \brief Get the current timestamp of USRP */
|
||||
openair0_timestamp get_usrp_time(openair0_device *device);
|
||||
/*! \brief Set the RX frequency of USRP RF TARGET */
|
||||
int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
|
||||
//extern
|
||||
/*! \brief Initialize Openair ETHERNET target. It returns 0 if OK */
|
||||
int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
/*@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/** ethernet_lib : API to stream I/Q samples over standard ethernet
|
||||
*
|
||||
* Authors: Pedro Dinis <pedrodinis20@gmail.com>
|
||||
* Lucio Ferreira <lucio.ferreira@inov.pt>
|
||||
* Raymond Knopp <raymond.knopp@eurecom.fr>
|
||||
*
|
||||
* Changelog:
|
||||
* 06.10.2014: Initial version
|
||||
*/
|
||||
/*! \file ethernet_lib.c
|
||||
* \brief API to stream I/Q samples over standard ethernet
|
||||
* \author Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
@@ -50,198 +50,500 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "ethernet_lib.h"
|
||||
|
||||
#define DEFAULT_IF "eth0"
|
||||
#define BUF_SIZ 8960 /*Jumbo frame size*/
|
||||
#define MAX_INST 4
|
||||
//#define DEBUG 1
|
||||
|
||||
int sockfd[MAX_INST];
|
||||
struct sockaddr_in dest_addr[MAX_INST];
|
||||
int num_devices_eth = 0;
|
||||
int dest_addr_len[MAX_INST];
|
||||
|
||||
int i;
|
||||
int tx_len = 0;
|
||||
char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
|
||||
|
||||
|
||||
/**PDF: Initialization of UDP Socket to communicate with one DEST */
|
||||
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port)
|
||||
{
|
||||
/*! \fn static int eth_socket_init(openair0_device *device)
|
||||
* \brief initialization of UDP Socket to communicate with one destination
|
||||
* \param[in] *device openair device for which the socket will be created
|
||||
* \param[out]
|
||||
* \return 0 on success, otherwise -1
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static int eth_socket_init(openair0_device *device);
|
||||
|
||||
/**PDF: To be passed by input argument*/
|
||||
// DEST_port = 32000;
|
||||
struct sockaddr_in *dest = &dest_addr[Mod_id];
|
||||
/*! \fn static int eth_set_dev_conf(openair0_device *device)
|
||||
* \brief
|
||||
* \param[in] *device openair device
|
||||
* \param[out]
|
||||
* \return 0 on success, otherwise -1
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static int eth_set_dev_conf(openair0_device *device);
|
||||
|
||||
/*! \fn static int eth_get_dev_conf(openair0_device *device)
|
||||
* \brief
|
||||
* \param[in] *device openair device
|
||||
* \param[out]
|
||||
* \return 0 on success, otherwise -1
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static int eth_get_dev_conf(openair0_device *device);
|
||||
|
||||
|
||||
|
||||
int trx_eth_start(openair0_device *device) {
|
||||
|
||||
/* initialize socket */
|
||||
if (eth_socket_init(device)!=0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* RRH gets openair0 device configuration BBU sets openair0 device configuration*/
|
||||
if (device->func_type == BBU_FUNC) {
|
||||
return eth_set_dev_conf(device);
|
||||
} else {
|
||||
return eth_get_dev_conf(device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
|
||||
|
||||
int n_written=0,i;
|
||||
uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
int sendto_flag =0;
|
||||
sendto_flag|=MSG_DONTWAIT;
|
||||
|
||||
for (i=0;i<cc;i++) {
|
||||
/* buff[i] points to the position in tx buffer where the payload to be sent is
|
||||
buff2 points to the position in tx buffer where the packet header will be placed */
|
||||
void *buff2 = (void*)(buff[i]-header_size);
|
||||
|
||||
/* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
|
||||
int32_t temp0 = *(int32_t *)buff2;
|
||||
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
|
||||
|
||||
n_written = 0;
|
||||
|
||||
*(int16_t *)(buff2 + sizeof(int16_t))=1+(i<<1);
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
|
||||
|
||||
/* printf("[RRH]write mod_%d %d , len %d, buff %p antenna %d\n",
|
||||
Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
|
||||
|
||||
while(n_written < nsamps) {
|
||||
/* Send packet */
|
||||
if ((n_written += sendto(eth->sockfd[Mod_id],
|
||||
buff2,
|
||||
(nsamps<<2)+header_size,
|
||||
0,
|
||||
(struct sockaddr*)ð->dest_addr[Mod_id],
|
||||
dest_addr_len[Mod_id])) < 0) {
|
||||
perror("ETHERNET WRITE");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("Buffer head TX: nu=%d an_id=%d ts%d samples_send=%d i=%d data=%x\n",
|
||||
*(int16_t *)buff2,
|
||||
*(int16_t *)(buff2 + sizeof(int16_t)),
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
|
||||
n_written>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
|
||||
#endif
|
||||
|
||||
/* tx buffer values restored */
|
||||
*(int32_t *)buff2 = temp0;
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
|
||||
}
|
||||
return n_written;
|
||||
|
||||
}
|
||||
|
||||
int trx_eth_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
|
||||
|
||||
int bytes_received=0;
|
||||
int block_cnt=0;
|
||||
int ret=0,i;
|
||||
uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
|
||||
for (i=0;i<cc;i++) {
|
||||
/* buff[i] points to the position in rx buffer where the payload to be received will be placed
|
||||
buff2 points to the position in rx buffer where the packet header will be placed */
|
||||
void *buff2 = (void*)(buff[i]-header_size);
|
||||
|
||||
/* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
|
||||
int32_t temp0 = *(int32_t *)buff2;
|
||||
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
|
||||
|
||||
bytes_received=0;
|
||||
block_cnt=0;
|
||||
ret=0;
|
||||
|
||||
/* printf("[RRH] read mod_%d %d,len %d, buff %p antenna %d\n",
|
||||
Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
|
||||
|
||||
while(bytes_received < (int)((nsamps<<2))) {
|
||||
ret=recvfrom(eth->sockfd[Mod_id],
|
||||
buff2+bytes_received,
|
||||
(nsamps<<2)+header_size-bytes_received,
|
||||
0,//MSG_DONTWAIT,
|
||||
(struct sockaddr *)ð->dest_addr[Mod_id],
|
||||
(socklen_t *)&dest_addr_len[Mod_id]);
|
||||
|
||||
if (ret==-1) {
|
||||
if (errno == EAGAIN) {
|
||||
perror("ETHERNET READ: ");
|
||||
return((nsamps<<2) + header_size);
|
||||
} else if (errno == EWOULDBLOCK) {
|
||||
block_cnt++;
|
||||
usleep(10);
|
||||
|
||||
if (block_cnt == 100) return(-1);
|
||||
}
|
||||
} else {
|
||||
bytes_received+=ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("Buffer head RX: nu=%d an_id=%d ts%d samples_recv=%d i=%d data=%x\n",
|
||||
*(int16_t *)buff2,
|
||||
*(int16_t *)(buff2 + sizeof(int16_t)),
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
|
||||
ret>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
|
||||
#endif
|
||||
|
||||
/* store the timestamp value from packet's header */
|
||||
*timestamp = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
|
||||
|
||||
/* tx buffer values restored */
|
||||
*(int32_t *)buff2 = temp0;
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
|
||||
}
|
||||
return nsamps;
|
||||
|
||||
}
|
||||
|
||||
void trx_eth_end(openair0_device *device) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
/*destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
|
||||
if ( close(eth->sockfd[Mod_id]) <0 ) {
|
||||
perror("ETHERNET: Failed to close socket");
|
||||
exit(0);
|
||||
} else {
|
||||
printf("[RRH] socket for mod_id %d has been successfully closed.\n",Mod_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
|
||||
|
||||
int Mod_id = device->Mod_id;
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
|
||||
/* BBU sends a message to RRH */
|
||||
if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)ð->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
|
||||
perror("ETHERNET: ");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
|
||||
/* RRH receives from BBU a message */
|
||||
if (recvfrom(eth->sockfd[Mod_id],
|
||||
msg,
|
||||
msg_len,
|
||||
0,
|
||||
(struct sockaddr *)ð->dest_addr[Mod_id],
|
||||
(socklen_t *)&dest_addr_len[Mod_id])==-1) {
|
||||
perror("ETHERNET: ");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eth_set_dev_conf(openair0_device *device) {
|
||||
|
||||
int Mod_id = device->Mod_id;
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
void *msg;
|
||||
ssize_t msg_len;
|
||||
|
||||
|
||||
/* a BBU client sents to RRH a set of configuration parameters (openair0_config_t)
|
||||
so that RF front end is configured appropriately and
|
||||
frame/packet size etc. can be set */
|
||||
|
||||
msg=malloc(sizeof(openair0_config_t));
|
||||
msg_len=sizeof(openair0_config_t);
|
||||
memcpy(msg,(void*)&device->openair0_cfg,msg_len);
|
||||
|
||||
if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)ð->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
|
||||
perror("ETHERNET: ");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eth_get_dev_conf(openair0_device *device) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
char str[INET_ADDRSTRLEN];
|
||||
void *msg;
|
||||
ssize_t msg_len;
|
||||
|
||||
msg=malloc(sizeof(openair0_config_t));
|
||||
msg_len=sizeof(openair0_config_t);
|
||||
|
||||
/* RRH receives from BBU openair0_config_t */
|
||||
if (recvfrom(eth->sockfd[Mod_id],
|
||||
msg,
|
||||
msg_len,
|
||||
0,
|
||||
(struct sockaddr *)ð->dest_addr[Mod_id],
|
||||
(socklen_t *)&dest_addr_len[Mod_id])==-1) {
|
||||
perror("ETHERNET: ");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
memcpy((void*)&device->openair0_cfg,msg,msg_len);
|
||||
inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
|
||||
device->openair0_cfg.remote_port =ntohs(eth->dest_addr[Mod_id].sin_port);
|
||||
device->openair0_cfg.remote_ip=str;
|
||||
/*apply additional configuration*/
|
||||
//ethernet_tune (device, RING_PAR);
|
||||
// printf("[RRH] write mod_%d %d to %s:%d\n",Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int trx_eth_stop(int card) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_eth_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_eth_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_eth_get_stats(openair0_device* device) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_eth_reset_stats(openair0_device* device) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int eth_socket_init(openair0_device *device) {
|
||||
|
||||
int i = 0;
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
char str[INET_ADDRSTRLEN];
|
||||
|
||||
const char *dest_ip;
|
||||
int dest_port=0;
|
||||
|
||||
if (device->func_type == RRH_FUNC ) {
|
||||
dest_ip = device->openair0_cfg.my_ip;
|
||||
dest_port = device->openair0_cfg.my_port;
|
||||
printf("[RRH] ip addr %s port %d\n",dest_ip, dest_port);
|
||||
} else {
|
||||
dest_ip = device->openair0_cfg.remote_ip;
|
||||
dest_port = device->openair0_cfg.remote_port;
|
||||
printf("[BBU] ip addr %s port %d\n",dest_ip, dest_port);
|
||||
}
|
||||
|
||||
/* Open RAW socket to send on */
|
||||
|
||||
if ((sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||
if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||
perror("ETHERNET: Error opening socket");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bzero((void *)dest,sizeof(struct sockaddr));
|
||||
dest->sin_family = AF_INET;
|
||||
dest->sin_addr.s_addr=inet_addr(dest_ip);
|
||||
dest->sin_port=htons(dest_port);
|
||||
dest_addr_len[Mod_id] = sizeof(struct sockaddr);
|
||||
|
||||
inet_ntop(AF_INET, &(dest->sin_addr), str, INET_ADDRSTRLEN);
|
||||
printf("Connecting to %s:%d\n",str,ntohs(dest->sin_port));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ethernet_write_data(int Mod_id, openair0_timestamp timestamp, const void **buff, int antenna_id, int nsamps)
|
||||
{
|
||||
|
||||
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp)-(sizeof(int16_t)*2);
|
||||
int32_t temp0 = *(int32_t *)buff2;
|
||||
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2+(sizeof(int16_t)*2));
|
||||
|
||||
int n_written;
|
||||
|
||||
n_written = 0;
|
||||
((int16_t *)buff2)[0] = 1+(antenna_id<<1);
|
||||
((int16_t *)buff2)[1] = nsamps;
|
||||
*((openair0_timestamp *)(buff2+(sizeof(int16_t)*2))) = timestamp;
|
||||
// printf("Timestamp TX sent : %d\n",timestamp);
|
||||
|
||||
// printf("buffer head : %d %d %d %d \n",((int16_t *)buff2)[0],((int16_t *)buff2)[1],((int16_t *)buff2)[2],((int16_t *)buff2)[3]);
|
||||
while(n_written < nsamps) {
|
||||
/* Send packet */
|
||||
if ((n_written += sendto(sockfd[Mod_id],
|
||||
buff2,
|
||||
(nsamps<<2)+sizeof(openair0_timestamp)+(2*sizeof(int16_t)),
|
||||
0,
|
||||
(struct sockaddr*)&dest_addr[Mod_id],
|
||||
dest_addr_len[Mod_id])) < 0) {
|
||||
printf("Send failed for Mod_id %d\n",Mod_id);
|
||||
perror("ETHERNET:");
|
||||
exit(-1);
|
||||
}
|
||||
/* initialize destination address */
|
||||
for (i=0; i< MAX_INST; i++) {
|
||||
bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
|
||||
}
|
||||
|
||||
*(int32_t *)buff2 = temp0;
|
||||
*(openair0_timestamp *)(buff2+2*sizeof(int16_t)) = temp1;
|
||||
return n_written;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int antenna_id, int nsamps)
|
||||
{
|
||||
|
||||
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp);
|
||||
int bytes_received;
|
||||
int block_cnt;
|
||||
int ret;
|
||||
openair0_timestamp temp = *(openair0_timestamp*)(buff2);
|
||||
int16_t mesg[2];
|
||||
char str[INET_ADDRSTRLEN];
|
||||
|
||||
//mesg[0] = 0+(antenna_id<<1);
|
||||
//mesg[1] = nsamps;
|
||||
|
||||
inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
|
||||
// send command RX for nsamps samples
|
||||
// printf("requesting %d samples from (%s:%d)\n",nsamps,str,ntohs(dest_addr[Mod_id].sin_port));
|
||||
|
||||
//sendto(sockfd[Mod_id],mesg,4,0,(struct sockaddr *)&dest_addr[Mod_id],dest_addr_len[Mod_id]);
|
||||
|
||||
bytes_received=0;
|
||||
block_cnt=0;
|
||||
|
||||
while(bytes_received < (int)((nsamps<<2))) {
|
||||
//printf("requesting %d bytes\n",(nsamps<<2));
|
||||
ret=recvfrom(sockfd[Mod_id],
|
||||
buff2+bytes_received,
|
||||
(nsamps<<2)+sizeof(openair0_timestamp)-bytes_received,
|
||||
0,//MSG_DONTWAIT,
|
||||
(struct sockaddr *)&dest_addr[Mod_id],
|
||||
&dest_addr_len[Mod_id]);
|
||||
|
||||
//printf("bytes_received %d (ret %d)\n",bytes_received+ret,ret);
|
||||
if (ret==-1) {
|
||||
if (errno == EAGAIN) {
|
||||
perror("ETHERNET: ");
|
||||
return((nsamps<<2)+sizeof(openair0_timestamp));
|
||||
} else if (errno == EWOULDBLOCK) {
|
||||
block_cnt++;
|
||||
usleep(10);
|
||||
|
||||
if (block_cnt == 100) return(-1);
|
||||
}
|
||||
// bzero((void *)dest,sizeof(struct sockaddr_in));
|
||||
eth->dest_addr[Mod_id].sin_family = AF_INET;
|
||||
inet_pton(AF_INET,dest_ip,&(eth->dest_addr[Mod_id].sin_addr.s_addr));
|
||||
eth->dest_addr[Mod_id].sin_port=htons(dest_port);
|
||||
dest_addr_len[Mod_id] = sizeof(struct sockaddr_in);
|
||||
inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
|
||||
|
||||
/* if RRH, then I am the server, so bind */
|
||||
if (device->func_type == RRH_FUNC ) {
|
||||
if (bind(eth->sockfd[Mod_id],(struct sockaddr *)ð->dest_addr[Mod_id], dest_addr_len[Mod_id])<0) {
|
||||
perror("ETHERNET: Cannot bind to socket");
|
||||
exit(0);
|
||||
} else {
|
||||
bytes_received+=ret;
|
||||
printf("[RRH] binding mod_%d to %s:%d\n",Mod_id,str,ntohs(eth->dest_addr[Mod_id].sin_port));
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("[BBU] Connecting to %s:%d\n",str,ntohs(eth->dest_addr[Mod_id].sin_port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ethernet_tune(openair0_device *device , eth_opt_t option) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id=device->Mod_id;
|
||||
|
||||
unsigned int sndbuf_size=0, rcvbuf_size=0;
|
||||
struct timeval snd_timeout, rcv_timeout;
|
||||
struct ifreq ifr;
|
||||
char system_cmd[256];
|
||||
char* if_name=DEFAULT_IF;
|
||||
|
||||
/****************** socket level options ************************/
|
||||
if (option== SND_BUF_SIZE) { /* transmit socket buffer size */
|
||||
if (setsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_SNDBUF,
|
||||
&sndbuf_size,sizeof(sndbuf_size))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf( "sndbuf_size= %d bytes\n", sndbuf_size);
|
||||
}
|
||||
} else if (option== RCV_BUF_SIZE) { /* receive socket buffer size */
|
||||
if (setsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_RCVBUF,
|
||||
&rcvbuf_size,sizeof(rcvbuf_size))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf( "rcvbuf_size= %d bytes\n", rcvbuf_size);
|
||||
}
|
||||
} else if (option==RCV_TIMEOUT) {
|
||||
rcv_timeout.tv_sec = 0;
|
||||
rcv_timeout.tv_usec = 180;//less than rt_period
|
||||
if (setsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_RCVTIMEO,
|
||||
(char *)&rcv_timeout,sizeof(rcv_timeout))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf( "rcv_timeout= %d usecs\n", rcv_timeout.tv_usec);
|
||||
}
|
||||
} else if (option==SND_TIMEOUT) {
|
||||
snd_timeout.tv_sec = 0;
|
||||
snd_timeout.tv_usec = 180;//less than rt_period
|
||||
if (setsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_SNDTIMEO,
|
||||
(char *)&snd_timeout,sizeof(snd_timeout))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf( "snd_timeout= %d usecs\n", snd_timeout.tv_usec);
|
||||
}
|
||||
}
|
||||
|
||||
/******************* interface level options *************************/
|
||||
else if (option==MTU_SIZE) { /* change MTU of the eth interface */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_mtu =8960;
|
||||
if (ioctl(eth->sockfd[Mod_id],SIOCSIFMTU,(caddr_t)&ifr) < 0 )
|
||||
perror ("[ETHERNET] Can't set the MTU");
|
||||
else
|
||||
printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
|
||||
} else if (option==TX_Q_LEN) { /* change TX queue length of eth interface */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_qlen =3000 ;
|
||||
if (ioctl(eth->sockfd[Mod_id],SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
|
||||
perror ("[ETHERNET] Can't set the txqueuelen");
|
||||
else
|
||||
printf("[ETHERNET] %s txqueuelen size has changed to %d\n",DEFAULT_IF,ifr.ifr_qlen);
|
||||
|
||||
|
||||
//printf("buffer head : %x %x %x %x \n",((int32_t *)buff2)[0],((int32_t *)buff2)[1],((int32_t *)buff2)[2],((int32_t *)buff2)[3]);
|
||||
*timestamp = *(openair0_timestamp *)(buff2);
|
||||
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
|
||||
*(openair0_timestamp *)(buff2) = temp;
|
||||
return nsamps;
|
||||
|
||||
/******************* device level options *************************/
|
||||
} else if (option==COALESCE_PAR) {
|
||||
if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs 3",DEFAULT_IF) > 0) {
|
||||
system(system_cmd);
|
||||
printf("[ETHERNET] Coalesce parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set coalesce parameters\n");
|
||||
}
|
||||
|
||||
} else if (option==PAUSE_PAR ) {
|
||||
if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",DEFAULT_IF) > 0) {
|
||||
system(system_cmd);
|
||||
printf("[ETHERNET] Pause parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set pause parameters\n");
|
||||
}
|
||||
} else if (option==RING_PAR ) {
|
||||
if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s rx 4096 tx 4096",DEFAULT_IF) > 0) {
|
||||
system(system_cmd);
|
||||
printf("[ETHERNET] Ring parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set ring parameters\n");
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int trx_eth_start(openair0_device *openair0)
|
||||
{
|
||||
|
||||
int16_t mesg[2];
|
||||
int Mod_id;
|
||||
int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
Mod_id = openair0->openair0_cfg.Mod_id;
|
||||
ethernet_socket_init(openair0->openair0_cfg.Mod_id, openair0->openair0_cfg.rrh_ip,openair0->openair0_cfg.rrh_port);
|
||||
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
|
||||
int card = 0;
|
||||
memset(eth, 0, sizeof(eth_state_t));
|
||||
eth->buffer_size = (unsigned int)openair0_cfg[card].samples_per_packet*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
|
||||
eth->sample_rate = (unsigned int)openair0_cfg[card].sample_rate;
|
||||
device->priv = eth;
|
||||
|
||||
mesg[0] = 1 + 0; //antenna index is 0, to be replaced by the number of active antennas
|
||||
mesg[1] = openair0->openair0_cfg.samples_per_packet;
|
||||
|
||||
sendto(sockfd[Mod_id],mesg,4,0,(struct sockaddr *)&dest_addr[Mod_id],dest_addr_len[Mod_id]);
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void trx_eth_write(openair0_device *device, openair0_timestamp timestamp, const void **buff, int nsamps, int cc, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<cc; i++)
|
||||
ethernet_write_data(device->Mod_id,timestamp,buff,i,nsamps);
|
||||
}
|
||||
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int cc)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0; i<cc; i++)
|
||||
return(ethernet_read_data(device->Mod_id,ptimestamp,buff,i,nsamps));
|
||||
|
||||
}
|
||||
|
||||
void trx_eth_end(openair0_device *device)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int num_devices = 0;
|
||||
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
|
||||
printf("ETHERNET: Initializing openair0_device\n");
|
||||
device->Mod_id = num_devices++;
|
||||
device->trx_start_func = trx_eth_start;
|
||||
device->trx_end_func = trx_eth_end;
|
||||
device->trx_read_func = trx_eth_read;
|
||||
device->trx_write_func = trx_eth_write;
|
||||
printf("ETHERNET: Initializing openair0_device for %s ...\n", ((device->func_type == BBU_FUNC) ? "BBU": "RRH"));
|
||||
device->Mod_id = num_devices_eth++;
|
||||
device->trx_start_func = trx_eth_start;
|
||||
device->trx_request_func = trx_eth_request;
|
||||
device->trx_reply_func = trx_eth_reply;
|
||||
device->trx_write_func = trx_eth_write;
|
||||
device->trx_read_func = trx_eth_read;
|
||||
device->trx_get_stats_func = trx_eth_get_stats;
|
||||
device->trx_reset_stats_func = trx_eth_reset_stats;
|
||||
device->trx_end_func = trx_eth_end;
|
||||
device->trx_stop_func = trx_eth_stop;
|
||||
device->trx_set_freq_func = trx_eth_set_freq;
|
||||
device->trx_set_gains_func = trx_eth_set_gains;
|
||||
|
||||
memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,42 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/*! \file ethernet_lib.h
|
||||
* \brief API to stream I/Q samples over standard ethernet
|
||||
* \author Katerina Trilyraki, Navid Nikaein
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <stdio.h>
|
||||
@@ -8,8 +47,107 @@
|
||||
#include <net/if.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port);
|
||||
#define MAX_INST 4
|
||||
#define DEFAULT_IF "lo"
|
||||
#define BUF_SIZ 8960 /*Jumbo frame size*/
|
||||
|
||||
int ethernet_write_data(int Mod_id, const void *buff, int nsamps,int cc);
|
||||
typedef struct {
|
||||
|
||||
int ethernet_read_data(int Mod_id,void *buff, int nsamps,int cc);
|
||||
// opaque eth data struct
|
||||
//struct eth_if *dev;
|
||||
// An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
|
||||
|
||||
int sockfd[MAX_INST];
|
||||
struct sockaddr_in dest_addr[MAX_INST];
|
||||
|
||||
unsigned int buffer_size;
|
||||
unsigned int timeout_ns;
|
||||
|
||||
//struct eth_metadata meta_rx;
|
||||
//struct eth_metadata meta_tx;
|
||||
|
||||
unsigned int sample_rate;
|
||||
// time offset between transmiter timestamp and receiver timestamp;
|
||||
double tdiff;
|
||||
// use brf_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;
|
||||
int num_rx_errors;
|
||||
int num_tx_errors;
|
||||
|
||||
uint64_t tx_actual_nsamps; // actual number of samples transmitted
|
||||
uint64_t rx_actual_nsamps;
|
||||
uint64_t tx_nsamps; // number of planned samples
|
||||
uint64_t rx_nsamps;
|
||||
uint64_t tx_count; // number pf packets
|
||||
uint64_t rx_count;
|
||||
//openair0_timestamp rx_timestamp;
|
||||
|
||||
} eth_state_t;
|
||||
|
||||
#define ETH_META_STATUS_OVERRUN (1 << 0)
|
||||
#define ETH_META_STATUS_UNDERRUN (1 << 1)
|
||||
|
||||
struct eth_meta_data{
|
||||
uint64_t timestamp;
|
||||
uint32_t flags;
|
||||
uint32_t status;
|
||||
unsigned int actual_count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*!\brief packet header */
|
||||
typedef struct {
|
||||
/*!\brief packet's timestamp */
|
||||
openair0_timestamp timestamp;
|
||||
/*!\brief variable declared for alignment purposes (sample size=32 bit) */
|
||||
int16_t not_used;
|
||||
/*!\brief antenna port used to resynchronize */
|
||||
int16_t antenna_id;
|
||||
} header_t;
|
||||
|
||||
/*!\brief different options for ethernet tuning in socket and driver level */
|
||||
typedef enum {
|
||||
MIN_OPT = 0,
|
||||
/*!\brief socket send buffer size in bytes */
|
||||
SND_BUF_SIZE,
|
||||
/*!\brief socket receive buffer size in bytes */
|
||||
RCV_BUF_SIZE,
|
||||
/*!\brief receiving timeout */
|
||||
RCV_TIMEOUT,
|
||||
/*!\brief sending timeout */
|
||||
SND_TIMEOUT,
|
||||
/*!\brief maximun transmission unit size in bytes */
|
||||
MTU_SIZE,
|
||||
/*!\brief TX queue length */
|
||||
TX_Q_LEN,
|
||||
/*!\brief RX/TX ring parameters of ethernet device */
|
||||
RING_PAR,
|
||||
/*!\brief interruptions coalesence mechanism of ethernet device */
|
||||
COALESCE_PAR,
|
||||
/*!\brief pause parameters of ethernet device */
|
||||
PAUSE_PAR,
|
||||
MAX_OPT
|
||||
} eth_opt_t;
|
||||
|
||||
|
||||
|
||||
/*! \fn int ethernet_tune (openair0_device *device, eth_opt_t option)
|
||||
* \brief this function allows you to configure certain ethernet parameters in socket or device level
|
||||
* \param[in] openair0 device which bears the socket
|
||||
* \param[in] name of parameter to configure
|
||||
* \return 0 on success, otherwise -1
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
int ethernet_tune (openair0_device *device, eth_opt_t option);
|
||||
int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc) ;
|
||||
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int cc);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# PROMGEN: Xilinx Prom Generator P.49d
|
||||
# Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved.
|
||||
# PROMGEN: Xilinx Prom Generator P.20131013
|
||||
# Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved.
|
||||
|
||||
SOFTWARE_VERSION P.49d
|
||||
DATE 3/21/2014 - 17:31
|
||||
SOURCE /homes/ghaddab/riadh/openair0/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2/exmimo2_prom.mcs
|
||||
SOFTWARE_VERSION P.20131013
|
||||
DATE 6/16/2015 - 16:10
|
||||
SOURCE /homes/maatalla/openair/openair0/express-mimo2/backup_houssem/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2/exmimo2_prom.mcs
|
||||
DEVICE 8192K
|
||||
DATA_WIDTH 4
|
||||
FILL_DATA 0xFF
|
||||
SIGNATURE 0x41900D70
|
||||
SIGNATURE 0x41521D58
|
||||
START_ADDRESS 0x00000000 END_ADDRESS 0x00406577 DIRECTION_UP "express-mimo2.bit" 6slx150tfgg900
|
||||
|
||||
+140119
-140119
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
PROMGEN: Xilinx Prom Generator P.49d
|
||||
Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved.
|
||||
PROMGEN: Xilinx Prom Generator P.20131013
|
||||
Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved.
|
||||
|
||||
promgen -w -p mcs -c FF -o /homes/ghaddab/riadh/openair0/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2//exmimo2_prom -s 8192 -u 0000 express-mimo2.bit -spi
|
||||
promgen -w -p mcs -c FF -o /homes/maatalla/openair/openair0/express-mimo2/backup_houssem/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2//exmimo2_prom -s 8192 -u 0000 express-mimo2.bit -spi
|
||||
|
||||
PROM /homes/ghaddab/riadh/openair0/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2/exmimo2_prom.prm map: Fri Mar 21 17:31:05 2014
|
||||
PROM /homes/maatalla/openair/openair0/express-mimo2/backup_houssem/express-mimo2/grlib-gpl-1.1.0-b4113/designs/express-mimo2/exmimo2_prom.prm map: Tue Jun 16 16:10:48 2015
|
||||
|
||||
Calculating PROM checksum with fill value ff
|
||||
|
||||
@@ -11,7 +11,7 @@ Format Mcs86 (32-bit)
|
||||
Size 8192K
|
||||
PROM start 0000:0000
|
||||
PROM end 007f:ffff
|
||||
PROM checksum 41900d70
|
||||
PROM checksum 41521d58
|
||||
|
||||
Addr1 Addr2 Date File(s)
|
||||
0000:0000 0040:6577 Mar 21 17:30:57 2014 express-mimo2.bit
|
||||
0000:0000 0040:6577 Jun 16 16:10:43 2015 express-mimo2.bit
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
setMode -bs
|
||||
setCable -port auto
|
||||
Identify
|
||||
identifyMPM
|
||||
assignFile -p 1 -file "express-mimo2.bit"
|
||||
Program -p 1 -defaultVersion 0
|
||||
quit
|
||||
@@ -247,10 +247,10 @@ int openair0_stop_without_reset(int card)
|
||||
#define MY_RF_MODE (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
|
||||
#define RF_MODE_BASE (LNA1ON + RFBBNORM)
|
||||
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
// Initialize card
|
||||
exmimo_config_t *p_exmimo_config;
|
||||
// exmimo_config_t *p_exmimo_config;
|
||||
exmimo_id_t *p_exmimo_id;
|
||||
int ret;
|
||||
|
||||
@@ -276,7 +276,7 @@ int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cf
|
||||
printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[0]);
|
||||
}
|
||||
|
||||
p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr;
|
||||
// p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr;
|
||||
p_exmimo_id = openair0_exmimo_pci[0].exmimo_id_ptr;
|
||||
|
||||
printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", 0, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);
|
||||
@@ -356,14 +356,15 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
|
||||
for (ant=0; ant<4; ant++) {
|
||||
if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
|
||||
p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
|
||||
p_exmimo_config->rf.do_autocal[ant] = 1;
|
||||
p_exmimo_config->rf.do_autocal[ant] = 1;//openair0_cfg[card].autocal[ant];
|
||||
printf("card %d, antenna %d, autocal %d\n",card,ant,openair0_cfg[card].autocal[ant]);
|
||||
}
|
||||
|
||||
if (openair0_cfg[card].tx_freq[ant]) {
|
||||
p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX + TXLPFNORM + TXLPFEN + tx_filter);
|
||||
p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
|
||||
p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
|
||||
printf("openair0 : programming card %d TX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
|
||||
|
||||
}
|
||||
|
||||
if (openair0_cfg[card].rx_freq[ant]) {
|
||||
@@ -419,11 +420,11 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
|
||||
|
||||
int openair0_reconfig(openair0_config_t *openair0_cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
int ant, card;
|
||||
|
||||
exmimo_config_t *p_exmimo_config;
|
||||
exmimo_id_t *p_exmimo_id;
|
||||
// exmimo_id_t *p_exmimo_id;
|
||||
|
||||
if (!openair0_cfg) {
|
||||
printf("Error, openair0_cfg is null!!\n");
|
||||
@@ -433,7 +434,7 @@ int openair0_reconfig(openair0_config_t *openair0_cfg)
|
||||
for (card=0; card<openair0_num_detected_cards; card++) {
|
||||
|
||||
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
|
||||
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
|
||||
// p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
|
||||
|
||||
for (ant=0; ant<4; ant++) {
|
||||
if (openair0_cfg[card].tx_freq[ant]) {
|
||||
@@ -468,6 +469,22 @@ int openair0_reconfig(openair0_config_t *openair0_cfg)
|
||||
return(0);
|
||||
}
|
||||
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
|
||||
|
||||
if (exmimo_dump_config > 0) {
|
||||
// do a full configuration
|
||||
openair0_config(openair0_cfg,0);
|
||||
}
|
||||
else { // just change the frequencies in pci descriptor
|
||||
openair0_reconfig(openair0_cfg);
|
||||
}
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
|
||||
return(0);
|
||||
}
|
||||
|
||||
unsigned int *openair0_daq_cnt(void) {
|
||||
|
||||
|
||||
@@ -95,4 +95,7 @@ int openair0_stop_without_reset(int card);
|
||||
// return the DAQ block counter
|
||||
unsigned int *openair0_daq_cnt(void);
|
||||
|
||||
// set the TX and RX frequencies (card 0 only for now, to retain USRP compatibility)
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
close all
|
||||
clear all
|
||||
hold off
|
||||
|
||||
%gpib_card=0; % first GPIB PCI card in the computer
|
||||
%gpib_device=28; % this is configured in the signal generator Utilities->System->GPIB->Address menu
|
||||
smbv_ip_addr = "192.168.12.201";
|
||||
command = [getenv("OPENAIR_TARGETS") "/TEST/ROHDE_SCHWARZ/EthernetRawCommand.out"];
|
||||
|
||||
fc = 1907600e3;
|
||||
%fc = 2.6e9;
|
||||
%fc=700e6;
|
||||
|
||||
fs = 7680e3;
|
||||
fref = fc+fs/4;
|
||||
|
||||
power_dBm = [-70 -80 -90]; %needs to be adjusted based on carrier freq
|
||||
cables_loss_dB = 11; % we need to account for the power loss between the signal generator and the card input (splitter, cables)
|
||||
nb_meas = 10;
|
||||
|
||||
dual_tx = 0;
|
||||
tdd = 1;
|
||||
card = 0;
|
||||
limeparms;
|
||||
%rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+DMAMODE_TX)*[1 1 1 1];
|
||||
rf_mode = (RXEN+0+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM+DMAMODE_RX+0)*[1 1 1 1];
|
||||
freq_rx = fc*[1 1 1 1];
|
||||
freq_tx = freq_rx;
|
||||
tx_gain = 25*[1 1 1 1];
|
||||
rx_gain = 15*[1 1 1 1];
|
||||
%rf_local= [8254744 8255063 8257340 8257340]; %rf_local*[1 1 1 1];
|
||||
rf_local = [8254813 8255016 8254813 8254813]; %exmimo2_2
|
||||
%rf_rxdc = rf_rxdc*[1 1 1 1];
|
||||
%rf_rxdc = ((128+rxdc_I) + (128+rxdc_Q)*(2^8))*[1 1 1 1];
|
||||
rf_rxdc = [37059 35459 36300 36999]; %exmimo2_2
|
||||
rf_vcocal=rf_vcocal_19G*[1 1 1 1];
|
||||
eNBflag = 0;
|
||||
tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX;
|
||||
syncmode = SYNCMODE_FREE;
|
||||
%syncmode = [SYNCMODE_MASTER SYNCMODE_SLAVE];
|
||||
rffe_rxg_low = 63*[1 1 1 1];
|
||||
rffe_rxg_final = 63*[1 1 1 1];
|
||||
rffe_band = B19G_TDD*[1 1 1 1];
|
||||
autocal = [1 1 1 1];
|
||||
resampling_factor = [2 2 2 2];
|
||||
|
||||
|
||||
system(sprintf('%s %s ''*RST;*CLS''',command, smbv_ip_addr)); % reset and configure the signal generator
|
||||
%gpib_send(gpib_card,gpib_device,sprintf("POW %ddBm",power_dBm+cables_loss_dB));
|
||||
%gpib_send(gpib_card,gpib_device,'POW -14dBm');
|
||||
%gpib_send(gpib_card,gpib_device,'FREQ 1.91860GHz');
|
||||
%gpib_send(gpib_card,gpib_device,'FREQ 1.919225GHz');
|
||||
%gpib_send(gpib_card,gpib_device,'FREQ 1.909225GHz');
|
||||
system(sprintf('%s %s ''FREQ %ldHz''',command,smbv_ip_addr,fref));
|
||||
|
||||
%for card=1:oarf_get_num_detected_cards
|
||||
%oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
|
||||
%end
|
||||
|
||||
autocal = [0 0 0 0];
|
||||
|
||||
ALL_rxrfmode = [LNAByp LNAMed LNAMax];
|
||||
%ALL_rxrfmode = [LNAMax];
|
||||
ALL_gain = 0:10:30;
|
||||
|
||||
num_chains = 4*oarf_get_num_detected_cards;
|
||||
|
||||
SpN0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
%SpN1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
|
||||
N0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
%N1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
|
||||
S0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
S0_lin = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
%S1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
G0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
G1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
NF0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
NF1 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
NF2 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
SNR0 = zeros(length(ALL_rxrfmode),length(ALL_gain),num_chains);
|
||||
%SNR1 = zeros(length(ALL_rxrfmode),length(ALL_gain));
|
||||
|
||||
%keyboard
|
||||
|
||||
for mode_idx = 3
|
||||
LNA=ALL_rxrfmode(mode_idx);
|
||||
|
||||
system(sprintf('%s %s ''POW %d dBm''',command,smbv_ip_addr,power_dBm(mode_idx)+cables_loss_dB));
|
||||
|
||||
idx_gain = 1;
|
||||
for rx_gain=ALL_gain
|
||||
|
||||
rf_mode = (RXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNA+RFBBNORM+DMAMODE_RX)*[1 1 1 1];
|
||||
rx_gain = rx_gain * [1 1 1 1];
|
||||
|
||||
for card=1:oarf_get_num_detected_cards
|
||||
oarf_config_exmimo(card-1,freq_rx,freq_tx,tdd_config,syncmode(card),rx_gain,tx_gain,eNBflag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor);
|
||||
end
|
||||
sleep(1);
|
||||
|
||||
% signal measurement
|
||||
system(sprintf('%s %s ''OUTP:STAT ON''',command,smbv_ip_addr)); % activate output
|
||||
sleep(.5);
|
||||
%f1 = (7.68*(0:length(s(:,2))-1)/(length(s(:,2))))-3.84;
|
||||
f1 = (7.68*(0:307200-1)/307200)-3.84;
|
||||
%nidx = find(f1>=0.5 & f1<=1.5); %1MHz
|
||||
nidx = find(f1>=1.5 & f1<=2.5); %1MHz
|
||||
sidx = find(f1>=1.87 & f1<=1.97); %100kHz
|
||||
|
||||
SpN0_temp = 0;
|
||||
spn0_temp = 0;
|
||||
for k=1:nb_meas
|
||||
s=oarf_get_frame(0);
|
||||
sleep(.5);
|
||||
s = s - repmat(mean(s,1),size(s,1),1);
|
||||
|
||||
SpN0_temp = SpN0_temp + mean(abs(s).^2,1) - abs(mean(s,1)).^2;
|
||||
sf = fftshift(fft(s),1)/sqrt(length(s));
|
||||
%np = 10*log10(sum(abs(sf(nidx,:)).^2));
|
||||
%sp_temp = sp_temp + 10*log10(sum(abs(sf(sidx,:)).^2));
|
||||
spn0_temp = spn0_temp + sum(abs(sf).^2);
|
||||
end
|
||||
%SpN0(mode_idx,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
|
||||
%SpN1(mode_idx,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
|
||||
SpN0(mode_idx,idx_gain,:) = SpN0_temp/nb_meas;
|
||||
spn0 = spn0_temp/nb_meas;
|
||||
|
||||
%keyboard;
|
||||
|
||||
sf = fftshift(fft(s),1)/sqrt(length(s));
|
||||
figure(1);
|
||||
hold off
|
||||
plot(f1,20*log10(abs((sf(:,3)))),'r');
|
||||
hold on
|
||||
plot(f1(nidx),20*log10(abs(sf(nidx,3))),'b');
|
||||
plot(f1(sidx),20*log10(abs(sf(sidx,3))),'g');
|
||||
|
||||
title("Signal");
|
||||
ylim([0 200]);
|
||||
|
||||
% noise measurement
|
||||
system(sprintf('%s %s ''OUTP:STAT OFF''',command,smbv_ip_addr)); % deactivate output
|
||||
sleep(.5);
|
||||
|
||||
N0_temp = 0;
|
||||
np_temp = 0;
|
||||
np_temp_unit = 0;
|
||||
for k=1:nb_meas
|
||||
s=oarf_get_frame(0); %oarf_get_frame
|
||||
sleep(.5);
|
||||
s = s - repmat(mean(s,1),size(s,1),1);
|
||||
|
||||
N0_temp = N0_temp + mean(abs(s).^2,1) - abs(mean(s,1)).^2;
|
||||
%N1(idx_power,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
|
||||
sf = fftshift(fft(s),1)/sqrt(length(s));
|
||||
np_temp = np_temp + sum(abs(sf).^2);
|
||||
np_temp_unit = np_temp_unit + sum(abs(sf(nidx,:)).^2);
|
||||
end
|
||||
N0(mode_idx,idx_gain,:) = N0_temp/nb_meas;
|
||||
%N0(mode_idx,idx_gain,:) = mean(abs(s).^2,1) - abs(mean(s,1)).^2;
|
||||
%N1(mode_idx,idx_gain) = mean(abs(s(:,2)).^2) - abs(mean(s(:,2))).^2;
|
||||
%G1(mode_idx,idx_gain,:) = sp - power_dBm(mode_idx);
|
||||
np = np_temp/nb_meas;
|
||||
snr = 10*log10((spn0-np)./np); %measured snr
|
||||
snr_real = power_dBm(mode_idx) - (-174 + 10*log10(7.68e6)); %signal over thermal noise
|
||||
|
||||
np_unit = np_temp_unit/nb_meas;
|
||||
snr_output_unit = 10*log10((spn0-np_unit)./np_unit); %measured snr
|
||||
snr_input_unit = power_dBm(mode_idx) - (-174 + 10*log10(1e6)); %signal over thermal noise
|
||||
|
||||
NF1(mode_idx,idx_gain,:) = snr_real - snr;
|
||||
NF2(mode_idx,idx_gain,:) = snr_input_unit - snr_output_unit;
|
||||
|
||||
sf = fftshift(fft(s),1)/sqrt(length(s));
|
||||
figure(2);
|
||||
hold off
|
||||
plot(f1,20*log10(abs((sf(:,3)))),'r');
|
||||
title("Noise");
|
||||
ylim([0 200]);
|
||||
|
||||
% do some plausibility checks
|
||||
% if ((N0(mode_idx,idx_gain) > SpN0(mode_idx,idx_gain)) ||
|
||||
% (N1(mode_idx,idx_gain) > SpN1(mode_idx,idx_gain)))
|
||||
% error("something is wrong");
|
||||
% end
|
||||
|
||||
S0_lin(mode_idx,idx_gain,:) = SpN0(mode_idx,idx_gain,:)-N0(mode_idx,idx_gain,:);
|
||||
S0_lin(mode_idx,idx_gain,S0_lin(mode_idx,idx_gain,:)<0) = 0;
|
||||
S0(mode_idx,idx_gain,:) = 10*log10(S0_lin(mode_idx,idx_gain,:));
|
||||
%S1(mode_idx,idx_gain) = 10*log10(SpN1(mode_idx,idx_gain)-N1(mode_idx,idx_gain));
|
||||
G0(mode_idx,idx_gain,:) = S0(mode_idx,idx_gain,:) - power_dBm(mode_idx);
|
||||
%G1(mode_idx,idx_gain) = S1(mode_idx,idx_gain) - power_dBm;
|
||||
NF0(mode_idx,idx_gain,:) = 10*log10(N0(mode_idx,idx_gain,:)) - G0(mode_idx,idx_gain,:) + 105; % 108 is the thermal noise
|
||||
%NF1(mode_idx,idx_gain) = 10*log10(N1(mode_idx,idx_gain)) - G1(mode_idx,idx_gain) + 105;
|
||||
SNR0(mode_idx,idx_gain,:) = S0(mode_idx,idx_gain,:)-10*log10(N0(mode_idx,idx_gain,:));
|
||||
%SNR1(mode_idx,idx_gain) = S1(mode_idx,idx_gain)-10*log10(N1(mode_idx,idx_gain));
|
||||
|
||||
%printf(' %d: Signal strength (%f,%f), Gain (%f %f), N (%f %f) SNR (%f %f) NF (%f %f)\n',
|
||||
% rx_gain(1), S0(mode_idx,idx_gain),S1(mode_idx,idx_gain),
|
||||
% G0(mode_idx,idx_gain),G1(mode_idx,idx_gain),
|
||||
% 10*log10(N0(mode_idx,idx_gain)),10*log10(N1(mode_idx,idx_gain)),
|
||||
% SNR0(mode_idx,idx_gain),SNR1(mode_idx,idx_gain),
|
||||
% NF0(mode_idx,idx_gain),NF1(mode_idx,idx_gain));
|
||||
%fflush(stdout);
|
||||
%fprintf(fid,'%d, %d, %d, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n',
|
||||
%power_dBm,gain2391,gain9862, S0,S1,G0,G1,10*log10(N0),10*log10(N1),SNR0,SNR1,NF0,NF1);
|
||||
%keyboard
|
||||
|
||||
figure(3)
|
||||
hold off
|
||||
plot(ALL_gain,G0(:,:,1),'o-','markersize',10)
|
||||
hold on
|
||||
plot(ALL_gain,G0(:,:,2),'x-','markersize',10)
|
||||
plot(ALL_gain,G0(:,:,3),'s-','markersize',10)
|
||||
plot(ALL_gain,G0(:,:,4),'d-','markersize',10)
|
||||
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
|
||||
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
|
||||
title('Gains')
|
||||
xlabel('rx gains (dB)')
|
||||
ylabel('NF (dB)')
|
||||
|
||||
figure(4)
|
||||
hold off
|
||||
plot(ALL_gain,NF0(:,:,1),'o-','markersize',10)
|
||||
hold on
|
||||
plot(ALL_gain,NF0(:,:,2),'x-','markersize',10)
|
||||
plot(ALL_gain,NF0(:,:,3),'s-','markersize',10)
|
||||
plot(ALL_gain,NF0(:,:,4),'d-','markersize',10)
|
||||
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
|
||||
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
|
||||
title('Averaged Noise Figure measured in time domain')
|
||||
xlabel('rx gains (dB)')
|
||||
ylabel('NF (dB)')
|
||||
|
||||
figure(5)
|
||||
hold off
|
||||
plot(ALL_gain,NF1(:,:,1),'o-','markersize',10)
|
||||
hold on
|
||||
plot(ALL_gain,NF1(:,:,2),'x-','markersize',10)
|
||||
plot(ALL_gain,NF1(:,:,3),'s-','markersize',10)
|
||||
plot(ALL_gain,NF1(:,:,4),'d-','markersize',10)
|
||||
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
|
||||
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
|
||||
title('Averaged Noise Figure measured in frequency domain')
|
||||
xlabel('rx gains (dB)')
|
||||
ylabel('NF (dB)')
|
||||
|
||||
|
||||
figure(6)
|
||||
hold off
|
||||
plot(ALL_gain,NF2(:,:,1),'o-','markersize',10)
|
||||
hold on
|
||||
plot(ALL_gain,NF2(:,:,2),'x-','markersize',10)
|
||||
plot(ALL_gain,NF2(:,:,3),'s-','markersize',10)
|
||||
plot(ALL_gain,NF2(:,:,4),'d-','markersize',10)
|
||||
%legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1');
|
||||
legend('Byp RX0','Med RX0','Max RX0','Byp RX1','Med RX1','Max RX1','Byp RX2','Med RX2','Max RX2','Byp RX3','Med RX3','Max RX3');
|
||||
title('Unit Bandwidth Noise Figure measured in frequency domain')
|
||||
xlabel('rx gains (dB)')
|
||||
ylabel('NF (dB)')
|
||||
|
||||
idx_gain = idx_gain + 1;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
%gpib_send(gpib_card,gpib_device,'OUTP:STAT OFF'); % deactivate output
|
||||
|
||||
%l0 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G0;
|
||||
%l1 = [ALL_gain2391; ones(size(ALL_gain2391))].'\G1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +44,15 @@
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "common_lib.h"
|
||||
#ifdef __SSE4_1__
|
||||
# include <smmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef __AVX2__
|
||||
# include <immintrin.h>
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -54,7 +62,7 @@ typedef struct
|
||||
// --------------------------------
|
||||
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;
|
||||
@@ -116,12 +124,14 @@ static void trx_usrp_end(openair0_device *device)
|
||||
|
||||
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;
|
||||
//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, void **buff, int nsamps, int cc, int flags)
|
||||
|
||||
static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, 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);
|
||||
@@ -138,29 +148,59 @@ static void trx_usrp_write(openair0_device *device, openair0_timestamp timestamp
|
||||
else
|
||||
s->tx_stream->send(buff[0], nsamps, s->tx_md);
|
||||
s->tx_md.start_of_burst = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc)
|
||||
{
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
int samples_received=0,i,j;
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
#if defined(__x86_64) || defined(__i386__)
|
||||
#ifdef __AVX2__
|
||||
__m256i buff_tmp[2][nsamps>>3];
|
||||
nsamps2 = (nsamps+7)>>3;
|
||||
#else
|
||||
__m128i buff_tmp[2][nsamps>>2];
|
||||
nsamps2 = (nsamps+3)>>2;
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
int16x8_t buff_tmp[2][nsamps>>2];
|
||||
nsamps2 = (nsamps+3)>>2;
|
||||
#endif
|
||||
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
int samples_received=0,i;
|
||||
|
||||
if (cc>1) {
|
||||
// receive multiple channels (e.g. RF A and RF B)
|
||||
std::vector<void *> buff_ptrs;
|
||||
for (int i=0;i<cc;i++) buff_ptrs.push_back(buff[i]);
|
||||
for (int i=0;i<cc;i++) buff_ptrs.push_back(buff_tmp[i]);
|
||||
samples_received = s->rx_stream->recv(buff_ptrs, nsamps, s->rx_md);
|
||||
} else {
|
||||
// receive a single channel (e.g. from connector RF A)
|
||||
samples_received = s->rx_stream->recv(buff[0], nsamps, s->rx_md);
|
||||
samples_received = s->rx_stream->recv(buff_tmp[0], nsamps, s->rx_md);
|
||||
}
|
||||
|
||||
// bring RX data into 12 LSBs for softmodem RX
|
||||
for (int i=0;i<cc;i++) {
|
||||
for (int j=0; j<nsamps2; j++) {
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#ifdef __AVX2__
|
||||
((__m256i *)buff[i])[j] = _mm256_srai_epi16(buff_tmp[i][j],4);
|
||||
#else
|
||||
((__m128i *)buff[i])[j] = _mm_srai_epi16(buff_tmp[i][j],4);
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
((int16x8_t*)buff[i])[j] = vshrq_n_s16(buff_tmp[i][j],4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (samples_received < nsamps) {
|
||||
printf("[recv] received %d samples out of %d\n",samples_received,nsamps);
|
||||
|
||||
}
|
||||
|
||||
//handle the error code
|
||||
switch(s->rx_md.error_code){
|
||||
case uhd::rx_metadata_t::ERROR_CODE_NONE:
|
||||
@@ -179,6 +219,7 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
|
||||
s->rx_count += nsamps;
|
||||
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
|
||||
*ptimestamp = s->rx_timestamp;
|
||||
|
||||
return samples_received;
|
||||
}
|
||||
|
||||
@@ -195,7 +236,7 @@ static bool is_equal(double a, double b)
|
||||
return std::fabs(a-b) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg) {
|
||||
int trx_usrp_set_freq(openair0_device* device, openair0_config_t *openair0_cfg, int dummy) {
|
||||
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
@@ -223,16 +264,72 @@ int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *open
|
||||
|
||||
}
|
||||
|
||||
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {
|
||||
int trx_usrp_set_gains(openair0_device* device,
|
||||
openair0_config_t *openair0_cfg) {
|
||||
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[0]);
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]);
|
||||
::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(0);
|
||||
// limit to maximum gain
|
||||
if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) {
|
||||
|
||||
printf("RX Gain 0 too high, reduce by %f dB\n",
|
||||
openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] - gain_range.stop());
|
||||
exit(-1);
|
||||
}
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]);
|
||||
printf("Setting USRP RX gain to %f\n", openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int trx_usrp_stop(int card) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
rx_gain_calib_table_t calib_table[] = {
|
||||
{3500000000.0,46.0},
|
||||
{2660000000.0,53.0},
|
||||
{2300000000.0,54.0},
|
||||
{1880000000.0,55.0},
|
||||
{816000000.0,62.0},
|
||||
{-1,0}};
|
||||
|
||||
void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index) {
|
||||
|
||||
int i=0;
|
||||
// loop through calibration table to find best adjustment factor for RX frequency
|
||||
double min_diff = 6e9,diff;
|
||||
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
while (calib_table[i].freq>0) {
|
||||
diff = fabs(openair0_cfg->rx_freq[chain_index] - calib_table[i].freq);
|
||||
printf("cal %d: freq %f, offset %f, diff %f\n",
|
||||
i,calib_table[i].freq,calib_table[i].offset,diff);
|
||||
if (min_diff > diff) {
|
||||
min_diff = diff;
|
||||
openair0_cfg->rx_gain_offset[chain_index] = calib_table[i].offset;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int trx_usrp_get_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int trx_usrp_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
uhd::set_thread_priority_safe(1.0);
|
||||
usrp_state_t *s = (usrp_state_t*)malloc(sizeof(usrp_state_t));
|
||||
@@ -300,7 +397,19 @@ int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cf
|
||||
s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i);
|
||||
printf("Setting rx freq/gain on channel %lu/%lu\n",i,s->usrp->get_rx_num_channels());
|
||||
s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i);
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i],i);
|
||||
set_rx_gain_offset(&openair0_cfg[0],i);
|
||||
|
||||
::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i);
|
||||
// limit to maximum gain
|
||||
if (openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] > gain_range.stop()) {
|
||||
|
||||
printf("RX Gain %lu too high, lower by %f dB\n",i,openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop());
|
||||
exit(-1);
|
||||
}
|
||||
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i);
|
||||
printf("RX Gain %lu %f (%f) => %f (max %f)\n",i,
|
||||
openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i],
|
||||
openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop());
|
||||
}
|
||||
}
|
||||
for(i=0;i<s->usrp->get_tx_num_channels();i++) {
|
||||
@@ -367,10 +476,15 @@ int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cf
|
||||
|
||||
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;
|
||||
|
||||
device->trx_read_func = trx_usrp_read;
|
||||
device->trx_get_stats_func = trx_usrp_get_stats;
|
||||
device->trx_reset_stats_func = trx_usrp_reset_stats;
|
||||
device->trx_end_func = trx_usrp_end;
|
||||
device->trx_stop_func = trx_usrp_stop;
|
||||
device->trx_set_freq_func = trx_usrp_set_freq;
|
||||
device->trx_set_gains_func = trx_usrp_set_gains;
|
||||
|
||||
s->sample_rate = openair0_cfg[0].sample_rate;
|
||||
// TODO:
|
||||
// init tx_forward_nsamps based usrp_time_offset ex
|
||||
@@ -380,6 +494,5 @@ int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cf
|
||||
s->tx_forward_nsamps = 90;
|
||||
if(is_equal(s->sample_rate, (double)7.68e6))
|
||||
s->tx_forward_nsamps = 50;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user