Commit 5832204f authored by Clayton Shepard's avatar Clayton Shepard Committed by rdoost

Added Iris hardware support.

Signed-off-by: rdoost's avatarRahman Doost <doost@rice.edu>
parent c1f7678e
Pipeline #11169 failed with stage
in 0 seconds
......@@ -551,6 +551,15 @@ set(TPLIB_ETHERNET_SOURCE
)
add_library(oai_eth_transpro MODULE ${TPLIB_ETHERNET_SOURCE} )
include_directories("${OPENAIR_TARGETS}/ARCH/IRIS/USERSPACE/LIB/")
set(option_HWIRISLIB_lib "-l SoapySDR")
set(HWLIB_IRIS_SOURCE
${OPENAIR_TARGETS}/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp
)
add_library(oai_irisdevif MODULE ${HWLIB_IRIS_SOURCE})
target_include_directories(oai_irisdevif PRIVATE /usr/local/lib/SoapySDR/modules0.6/)
target_link_libraries(oai_irisdevif SoapySDR)
include_directories("${OPENAIR_TARGETS}/ARCH/mobipass/")
set(TPLIB_MOBIPASS_SOURCE
${OPENAIR_TARGETS}/ARCH/mobipass/interface.c
......@@ -1787,6 +1796,15 @@ include_directories(${CRYPTO_INCLUDE_DIRS})
if (${RF_BOARD} STREQUAL "OAI_USRP")
find_package(Boost REQUIRED)
include_directories(${LIBBOOST_INCLUDE_DIR})
elseif (${RF_BOARD} STREQUAL "OAI_IRIS")
include_directories("${OPENAIR_TARGETS}/ARCH/IRIS/USERSPACE/LIB/")
include_directories("/usr/local/include/")
set(HW_SOURCE ${HW_SOURCE}
${OPENAIR_TARGETS}/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp)
LINK_DIRECTORIES("/usr/local/lib")
set(option_HW_lib "-lSoapySDR -rdynamic -ldl")
endif (${RF_BOARD} STREQUAL "OAI_USRP")
pkg_search_module(OPENPGM openpgm-5.1 openpgm-5.2)
......
......@@ -107,7 +107,7 @@ Options
Rel8 limits the implementation to 3GPP Release 8 version
Rel10 limits the implementation to 3GPP Release 10 version
-w | --hardware
EXMIMO, USRP, BLADERF, ETHERNET, LMSSDR, None (Default)
EXMIMO, USRP, BLADERF, ETHERNET, LMSSDR, IRIS, None (Default)
Adds this RF board support (in external packages installation and in compilation)
-t | --transport protocol
ETHERNET , None
......@@ -231,7 +231,7 @@ function main() {
-w | --hardware)
HW="$2" #"${i#*=}"
# Use OAI_USRP as the key word USRP is used inside UHD driver
if [ "$HW" != "BLADERF" -a "$HW" != "USRP" -a "$HW" != "LMSSDR" -a "$HW" != "None" -a "$HW" != "EXMIMO" ] ; then
if [ "$HW" != "BLADERF" -a "$HW" != "USRP" -a "$HW" != "LMSSDR" -a "$HW" != "None" -a "$HW" != "EXMIMO" -a "$HW" != "IRIS" ] ; then
echo_fatal "Unknown HW type $HW will exit..."
else
if [ "$HW" == "USRP" ] ; then
......@@ -243,6 +243,9 @@ function main() {
if [ "$HW" == "LMSSDR" ] ; then
HW="OAI_LMSSDR"
fi
if [ "$HW" == "IRIS" ] ; then
HW="OAI_IRIS"
fi
echo_info "Setting hardware to: $HW"
fi
shift 2;;
......@@ -414,7 +417,9 @@ function main() {
DEADLINE_SCHEDULER_FLAG_USER="False"
elif [ "$HW" = "OAI_BLADERF" ] ; then
DEADLINE_SCHEDULER_FLAG_USER="False"
elif [ "$HW" = "OAI_LMSSDR" ] ; then
elif [ "$HW" = "OAI_LMSSDR" ] ; then
DEADLINE_SCHEDULER_FLAG_USER="False"
elif [ "$HW" = "OAI_IRIS" ] ; then
DEADLINE_SCHEDULER_FLAG_USER="False"
elif [ "$HW" = "None" ] ; then
DEADLINE_SCHEDULER_FLAG_USER="False"
......@@ -484,6 +489,13 @@ function main() {
flash_firmware_bladerf
fi
fi
if [ "$HW" == "OAI_IRIS" ] ; then
echo_info "installing packages for IRIS support"
check_install_soapy
#if [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then
# flash_firmware_iris
#fi
fi
echo_info "installing protobuf/protobuf-c for flexran agent support"
install_protobuf_from_source
install_protobuf_c_from_source
......@@ -756,6 +768,14 @@ function main() {
ln -sf liboai_lmssdrdevif.so liboai_device.so
ln -sf $dbin/liboai_lmssdrdevif.so.$REL $dbin/liboai_device.so
echo_info "liboai_device.so is linked to LMSSDR device library"
elif [ "$HW" == "OAI_IRIS" ] ; then
compilations \
$build_dir oai_irisdevif \
liboai_irisdevif.so $dbin/liboai_irisdevif.so.$REL
ln -s liboai_irisdevif.so liboai_device.so
ln -s $dbin/liboai_irisdevif.so.$REL $dbin/liboai_device.so
echo_info "liboai_device.so is linked to IRIS device library"
else
echo_info "liboai_device.so is not linked to any device library"
fi
......
......@@ -379,6 +379,74 @@ check_install_lmssdr_driver(){
}
install_soapy_from_source(){
soapy_install_log=$OPENAIR_DIR/cmake_targets/log/soapy_install_log.txt
echo_info "\nInstalling Soapy EcoSystem from source. The log file for Soapy installation is here: $soapy_install_log "
(
cd /tmp
echo "Downloading SoapySDR"
rm -rf /tmp/soapysdr
git clone https://github.com/pothosware/SoapySDR.git
cd soapysdr
#git checkout tags/release_003_010_001_001
mkdir -p build
cd build
$CMAKE ../
echo "Compiling SoapySDR"
make -j`nproc`
$SUDO make install
$SUDO ldconfig
cd /tmp
echo "Downloading SoapyRemote"
rm -rf /tmp/soapyremote
git clone https://github.com/pothosware/SoapyRemote.git
cd soapyremote
#git checkout tags/release_003_010_001_001
mkdir -p build
cd build
cmake ../
echo "Compiling SoapyRemote"
make -j`nproc`
$SUDO make install
$SUDO ldconfig
) >& $soapy_install_log
}
install_soapy_iris_from_source(){
iris_install_log=$OPENAIR_DIR/cmake_targets/log/iris_install_log.txt
echo_info "\nInstalling Iris driver from source. The log file for Iris driver installation is here: $iris_install_log "
(
cd /tmp
echo "Downloading SoapyIris"
rm -rf /tmp/sklk-soapyiris
git clone https://github.com/skylarkwireless/sklk-soapyiris.git
cd sklk-soapyiris
mkdir -p build
cd build
cmake ../
echo "Compiling SoapyIris"
make -j`nproc`
$SUDO make install
$SUDO ldconfig
) >& $iris_install_log
}
check_install_soapy () {
#if [[ "$OS_DISTRO" == "ubuntu" ]]; then
#first we remove old installation
$SUDO apt-get remove -y soapysdr soapysdr-server libsoapysdr-dev python-soapysdr python3-soapysdr soapysdr-module-remote || true
$SUDO add-apt-repository -y ppa:myriadrf/drivers
$SUDO apt-get update
$SUDO apt-get install -y soapysdr soapysdr-server libsoapysdr-dev python-soapysdr python3-soapysdr soapysdr-module-remote
#elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
# $SUDO $INSTALLER -y install software-properties-common python3-software-properties python-software-properties subversion git python3 python-numpy python3-numpy cmake swig python-dev
# install_soapy_from_source
#fi
install_soapy_iris_from_source
}
check_install_additional_tools (){
$SUDO $INSTALLER update -y
if [[ "$OS_DISTRO" == "ubuntu" ]]; then
......
......@@ -48,7 +48,7 @@ int set_device(openair0_device *device) {
case USRP_B200_DEV:
printf("[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
break;
case USRP_X300_DEV:
case USRP_X300_DEV:
printf("[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
break;
case BLADERF_DEV:
......@@ -57,6 +57,9 @@ case USRP_X300_DEV:
case LMSSDR_DEV:
printf("[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
break;
case IRIS_DEV:
printf("[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
break;
case NONE_DEV:
printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
break;
......
......@@ -95,6 +95,8 @@ typedef enum {
BLADERF_DEV,
/*!\brief device is LMSSDR (SoDeRa)*/
LMSSDR_DEV,
/*!\brief device is Iris */
IRIS_DEV,
/*!\brief device is NONE*/
NONE_DEV,
MAX_RF_DEV_TYPE
......
IRIS_OBJ += $(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/iris_lib.o
IRIS_FILE_OBJ += $(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp
IRIS_CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/COMMON -I$(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/COMMON
/** iris_lib.cpp
*
* \author: Rahman Doost-Mohammady : doost@rice.edu
*/
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Time.hpp>
//#include <boost/format.hpp>
#include <iostream>
#include <complex>
#include <fstream>
#include <cmath>
#include <time.h>
#include <limits>
#include "common/utils/LOG/log_extern.h"
#include "common_lib.h"
#include <chrono>
#ifdef __SSE4_1__
# include <smmintrin.h>
#endif
#ifdef __AVX2__
# include <immintrin.h>
#endif
#define SAMPLE_RATE_DOWN 1
/*! \brief Iris Configuration */
typedef struct {
// --------------------------------
// variables for Iris configuration
// --------------------------------
//! Iris device pointer
std::vector<SoapySDR::Device *> iris;
int device_num;
int rx_num_channels;
int tx_num_channels;
//create a send streamer and a receive streamer
//! Iris TX Stream
std::vector<SoapySDR::Stream *> txStream;
//! Iris RX Stream
std::vector<SoapySDR::Stream *> rxStream;
//! Sampling rate
double sample_rate;
//! time offset between transmiter timestamp and receiver timestamp;
double tdiff;
//! TX forward samples.
int tx_forward_nsamps; //166 for 20Mhz
// --------------------------------
// Debug and output control
// --------------------------------
//! Number of underflows
int num_underflows;
//! Number of overflows
int num_overflows;
//! Number of sequential errors
int num_seq_errors;
//! tx count
int64_t tx_count;
//! rx count
int64_t rx_count;
//! timestamp of RX packet
openair0_timestamp rx_timestamp;
} iris_state_t;
/*! \brief Called to start the Iris lime transceiver. Return 0 if OK, < 0 if error
@param device pointer to the device structure specific to the RF hardware target
*/
static int trx_iris_start(openair0_device *device) {
iris_state_t *s = (iris_state_t *) device->priv;
long long timeNs = s->iris[0]->getHardwareTime("") + 500000;
int flags = 0;
//flags |= SOAPY_SDR_HAS_TIME;
int r;
for (r = 0; r < s->device_num; r++) {
int ret = s->iris[r]->activateStream(s->rxStream[r], flags, timeNs, 0);
int ret2 = s->iris[r]->activateStream(s->txStream[r]);
if (ret < 0 | ret2 < 0)
return -1;
}
return 0;
}
/*! \brief Stop Iris
* \param card refers to the hardware index to use
*/
int trx_iris_stop(openair0_device *device) {
iris_state_t *s = (iris_state_t *) device->priv;
int r;
for (r = 0; r < s->device_num; r++) {
s->iris[r]->deactivateStream(s->txStream[r]);
s->iris[r]->deactivateStream(s->rxStream[r]);
}
return (0);
}
/*! \brief Terminate operation of the Iris lime transceiver -- free all associated resources
* \param device the hardware to use
*/
static void trx_iris_end(openair0_device *device) {
LOG_I(HW, "Closing Iris device.\n");
trx_iris_stop(device);
iris_state_t *s = (iris_state_t *) device->priv;
int r;
for (r = 0; r < s->device_num; r++) {
s->iris[r]->closeStream(s->txStream[r]);
s->iris[r]->closeStream(s->rxStream[r]);
SoapySDR::Device::unmake(s->iris[r]);
}
}
/*! \brief Called to send samples to the Iris 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
*/
static int
trx_iris_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
using namespace std::chrono;
static long long int loop = 0;
static long time_min = 0, time_max = 0, time_avg = 0;
struct timespec tp_start, tp_end;
long time_diff;
int ret = 0, ret_i = 0;
int flag = 0;
iris_state_t *s = (iris_state_t *) device->priv;
int nsamps2; // aligned to upper 32 or 16 byte boundary
#if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__
nsamps2 = (nsamps+7)>>3;
__m256i buff_tx[2][nsamps2];
#else
nsamps2 = (nsamps+3)>>2;
__m128i buff_tx[2][nsamps2];
#endif
#endif
// 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__
buff_tx[i][j] = _mm256_slli_epi16(((__m256i *)buff[i])[j],4);
#else
buff_tx[i][j] = _mm_slli_epi16(((__m128i *)buff[i])[j],4);
#endif
#endif
}
}
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_start);
// This hack was added by cws to help keep packets flowing
if (flags)
flag |= SOAPY_SDR_HAS_TIME;
else {
long long tempHack = s->iris[0]->getHardwareTime("");
return nsamps;
}
if (flags == 2 || flags == 1) { // start of burst
} else if (flags == 3 | flags == 4) {
flag |= SOAPY_SDR_END_BURST;
}
long long timeNs = SoapySDR::ticksToTimeNs(timestamp, s->sample_rate / SAMPLE_RATE_DOWN);
uint32_t *samps[2]; //= (uint32_t **)buff;
int r;
int m = s->tx_num_channels;
for (r = 0; r < s->device_num; r++) {
int samples_sent = 0;
samps[0] = (uint32_t *) buff_tx[m * r];
if (cc % 2 == 0)
samps[1] = (uint32_t *) buff_tx[m * r + 1]; //cws: it seems another thread can clobber these, so we need to save them locally.
#ifdef IRIS_DEBUG
int i;
for (i = 200; i < 216; i++)
printf("%d, ",((int16_t)(samps[0][i]>>16))>>4);
printf("\n");
//printf("\nHardware time before write: %lld, tx_time_stamp: %lld\n", s->iris[0]->getHardwareTime(""), timeNs);
#endif
ret = s->iris[r]->writeStream(s->txStream[r], (void **) samps, (size_t)(nsamps), flag, timeNs, 1000000);
if (ret < 0)
printf("Unable to write stream!\n");
else
samples_sent = ret;
if (samples_sent != nsamps)
printf("[xmit] tx samples %d != %d\n", samples_sent, nsamps);
}
return nsamps;
}
/*! \brief Receive samples from hardware.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
* the first channel. *ptimestamp is the time at which the first sample
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
* \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read
*/
static int trx_iris_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
int ret = 0;
static long long nextTime;
static bool nextTimeValid = false;
iris_state_t *s = (iris_state_t *) device->priv;
bool time_set = false;
long long timeNs = 0;
int flags;
int samples_received;
uint32_t *samps[2]; //= (uint32_t **)buff;
int r;
int m = s->rx_num_channels;
int nsamps2; // aligned to upper 32 or 16 byte boundary
#if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__
nsamps2 = (nsamps+7)>>3;
__m256i buff_tmp[2][nsamps2];
#else
nsamps2 = (nsamps+3)>>2;
__m128i buff_tmp[2][nsamps2];
#endif
#endif
for (r = 0; r < s->device_num; r++) {
flags = 0;
samples_received = 0;
samps[0] = (uint32_t *) buff_tmp[m * r];
if (cc % 2 == 0)
samps[1] = (uint32_t *) buff_tmp[m * r + 1];
flags = 0;
ret = s->iris[r]->readStream(s->rxStream[r], (void **) samps, (size_t)(nsamps), flags,
timeNs, 1000000);
if (ret < 0) {
if (ret == SOAPY_SDR_TIME_ERROR)
printf("[recv] Time Error in tx stream!\n");
else if (ret == SOAPY_SDR_OVERFLOW | (flags & SOAPY_SDR_END_ABRUPT))
printf("[recv] Overflow occured!\n");
else if (ret == SOAPY_SDR_TIMEOUT)
printf("[recv] Timeout occured!\n");
else if (ret == SOAPY_SDR_STREAM_ERROR)
printf("[recv] Stream (tx) error occured!\n");
else if (ret == SOAPY_SDR_CORRUPTION)
printf("[recv] Bad packet occured!\n");
break;
} else
samples_received = ret;
if (r == 0) {
if (samples_received == ret) // first batch
{
if (flags & SOAPY_SDR_HAS_TIME) {
s->rx_timestamp = SoapySDR::timeNsToTicks(timeNs, s->sample_rate / SAMPLE_RATE_DOWN);
*ptimestamp = s->rx_timestamp;
nextTime = timeNs;
nextTimeValid = true;
time_set = true;
//printf("1) time set %llu \n", *ptimestamp);
}
}
}
if (r == 0) {
if (samples_received == nsamps) {
if (flags & SOAPY_SDR_HAS_TIME) {
s->rx_timestamp = SoapySDR::timeNsToTicks(nextTime, s->sample_rate / SAMPLE_RATE_DOWN);
*ptimestamp = s->rx_timestamp;
nextTime = timeNs;
nextTimeValid = true;
time_set = true;
}
} else if (samples_received < nsamps)
printf("[recv] received %d samples out of %d\n", samples_received, nsamps);
s->rx_count += samples_received;
if (s->sample_rate != 0 && nextTimeValid) {
if (!time_set) {
s->rx_timestamp = SoapySDR::timeNsToTicks(nextTime, s->sample_rate / SAMPLE_RATE_DOWN);
*ptimestamp = s->rx_timestamp;
//printf("2) time set %llu, nextTime will be %llu \n", *ptimestamp, nextTime);
}
nextTime += SoapySDR::ticksToTimeNs(samples_received, s->sample_rate / SAMPLE_RATE_DOWN);
}
}
// 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
#endif
}
}
}
return samples_received;
}
/*! \brief Get current timestamp of Iris
* \param device the hardware to use
*/
openair0_timestamp get_iris_time(openair0_device *device) {
iris_state_t *s = (iris_state_t *) device->priv;
return SoapySDR::timeNsToTicks(s->iris[0]->getHardwareTime(""), s->sample_rate);
}
/*! \brief Compares two variables within precision
* \param a first variable
* \param b second variable
*/
static bool is_equal(double a, double b) {
return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
}
void *set_freq_thread(void *arg) {
openair0_device *device = (openair0_device *) arg;
iris_state_t *s = (iris_state_t *) device->priv;
int r, i;
printf("Setting Iris TX Freq %f, RX Freq %f\n", device->openair0_cfg[0].tx_freq[0],
device->openair0_cfg[0].rx_freq[0]);
// add check for the number of channels in the cfg
for (r = 0; r < s->device_num; r++) {
for (i = 0; i < s->iris[r]->getNumChannels(SOAPY_SDR_RX); i++) {
if (i < s->rx_num_channels)
s->iris[r]->setFrequency(SOAPY_SDR_RX, i, "RF", device->openair0_cfg[0].rx_freq[i]);
}
for (i = 0; i < s->iris[r]->getNumChannels(SOAPY_SDR_TX); i++) {
if (i < s->tx_num_channels)
s->iris[r]->setFrequency(SOAPY_SDR_TX, i, "RF", device->openair0_cfg[0].tx_freq[i]);
}
}
}
/*! \brief Set frequencies (TX/RX)
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \param dummy dummy variable not used
* \returns 0 in success
*/
int trx_iris_set_freq(openair0_device *device, openair0_config_t *openair0_cfg, int dont_block) {
iris_state_t *s = (iris_state_t *) device->priv;
pthread_t f_thread;
if (dont_block)
pthread_create(&f_thread, NULL, set_freq_thread, (void *) device);
else {
int r, i;
for (r = 0; r < s->device_num; r++) {
printf("Setting Iris TX Freq %f, RX Freq %f\n", openair0_cfg[0].tx_freq[0], openair0_cfg[0].rx_freq[0]);
for (i = 0; i < s->iris[r]->getNumChannels(SOAPY_SDR_RX); i++) {
if (i < s->rx_num_channels) {
s->iris[r]->setFrequency(SOAPY_SDR_RX, i, "RF", openair0_cfg[0].rx_freq[i]);
}
}
for (i = 0; i < s->iris[r]->getNumChannels(SOAPY_SDR_TX); i++) {
if (i < s->tx_num_channels) {
s->iris[r]->setFrequency(SOAPY_SDR_TX, i, "RF", openair0_cfg[0].tx_freq[i]);
}
}
}
}
return (0);
}
/*! \brief Set Gains (TX/RX)
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 in success
*/
int trx_iris_set_gains(openair0_device *device,
openair0_config_t *openair0_cfg) {
iris_state_t *s = (iris_state_t *) device->priv;
int r;
for (r = 0; r < s->device_num; r++) {
s->iris[r]->setGain(SOAPY_SDR_RX, 0, openair0_cfg[0].rx_gain[0]);
s->iris[r]->setGain(SOAPY_SDR_TX, 0, openair0_cfg[0].tx_gain[0]);
s->iris[r]->setGain(SOAPY_SDR_RX, 1, openair0_cfg[0].rx_gain[1]);
s->iris[r]->setGain(SOAPY_SDR_TX, 1, openair0_cfg[0].tx_gain[1]);
}
return (0);
}
/*! \brief Iris RX calibration table */
rx_gain_calib_table_t calib_table_iris[] = {
{3500000000.0, 83},
{2660000000.0, 83},
{2580000000.0, 83},
{2300000000.0, 83},
{1880000000.0, 83},
{816000000.0, 83},
{-1, 0}};
/*! \brief Set RX gain offset
* \param openair0_cfg RF frontend parameters set by application
* \param chain_index RF chain to apply settings to
* \returns 0 in success
*/
void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index, int bw_gain_adjust) {
int i = 0;
// loop through calibration table to find best adjustment factor for RX frequency
double min_diff = 6e9, diff, gain_adj = 0.0;
if (bw_gain_adjust == 1) {
switch ((int) openair0_cfg[0].sample_rate) {
case 30720000:
break;
case 23040000:
gain_adj = 1.25;
break;
case 15360000:
gain_adj = 3.0;
break;
case 7680000:
gain_adj = 6.0;
break;
case 3840000:
gain_adj = 9.0;
break;
case 1920000:
gain_adj = 12.0;
break;
default:
printf("unknown sampling rate %d\n", (int) openair0_cfg[0].sample_rate);
exit(-1);
break;
}
}
while (openair0_cfg->rx_gain_calib_table[i].freq > 0) {
diff = fabs(openair0_cfg->rx_freq[chain_index] - openair0_cfg->rx_gain_calib_table[i].freq);
printf("cal %d: freq %f, offset %f, diff %f\n",
i,
openair0_cfg->rx_gain_calib_table[i].freq,
openair0_cfg->rx_gain_calib_table[i].offset, diff);
if (min_diff > diff) {
min_diff = diff;
openair0_cfg->rx_gain_offset[chain_index] = openair0_cfg->rx_gain_calib_table[i].offset + gain_adj;
}
i++;
}
}
/*! \brief print the Iris statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_iris_get_stats(openair0_device *device) {
return (0);
}
/*! \brief Reset the Iris statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_iris_reset_stats(openair0_device *device) {