* add RRH gateway module, IQ transports, and its gtkwave template (experimental)
* update ethernet library and common lib * update runtime values of the lte-softmodem tx and rx threads based on an empirical model git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7709 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
@@ -362,14 +362,14 @@ elseif (${RF_BOARD} STREQUAL "OAI_BLADERF")
|
||||
${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
|
||||
)
|
||||
LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu/")
|
||||
set(option_HW_lib "bladeRF")
|
||||
|
||||
|
||||
elseif (${RF_BOARD} STREQUAL "ETHERNET")
|
||||
include_directories ("${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB")
|
||||
set(HW_SOURCE ${HW_SOURCE}
|
||||
${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
|
||||
)
|
||||
|
||||
${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
|
||||
)
|
||||
set(LOWLATENCY True)
|
||||
|
||||
elseif (${RF_BOARD} STREQUAL "CPRIGW")
|
||||
set(HW_SOURCE ${HW_SOURCE}
|
||||
${OPENAIR_TARGETS}/ARCH/CPRIGW/USERSPACE/LIB/cprigw_lib.c
|
||||
@@ -393,7 +393,7 @@ add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????")
|
||||
add_boolean_option(DISABLE_USE_NAS False "???")
|
||||
add_boolean_option(ENABLE_STANDALONE_EPC True "Compile MME, SGW and PGW in a single executable")
|
||||
add_boolean_option(EPC_BUILD False "???")
|
||||
add_boolean_option(LOWLATENCY True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14")
|
||||
add_boolean_option(LOWLATENCY True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14")
|
||||
add_boolean_option(NAS_ADDRESS_FIX False "specific to oaisim: for nasmesh driver")
|
||||
add_boolean_option(NAS_NETLINK False "???? Must be True to compile nasmesh driver without rtai")
|
||||
add_boolean_option(OAISIM False "specific to oaisim")
|
||||
@@ -1567,6 +1567,8 @@ add_executable(lte-softmodem-nos1
|
||||
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
|
||||
${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
|
||||
${OPENAIR_TARGETS}/COMMON/create_tasks.c
|
||||
#${OPENAIR2_DIR}/RRC/NAS/nas_config.c # enable if you want rrc to mount ip interface
|
||||
#${OPENAIR2_DIR}/RRC/NAS/rb_config.c
|
||||
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
|
||||
${HW_SOURCE}
|
||||
${RTAI_SOURCE}
|
||||
@@ -1711,6 +1713,36 @@ target_link_libraries (oai_sgw
|
||||
)
|
||||
endif(MESSAGE_CHART_GENERATOR)
|
||||
|
||||
|
||||
# rrh
|
||||
################################
|
||||
set(DRIVER2013)
|
||||
|
||||
#Note: only on RF type is currently supported for RRH
|
||||
add_executable(rrh_gw
|
||||
${OPENAIR_TARGETS}/RT/USER/rrh_gw.c
|
||||
${OPENAIR_TARGETS}/RT/USER/eNB_transport_IQ.c
|
||||
${OPENAIR_TARGETS}/RT/USER/UE_transport_IQ.c
|
||||
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
|
||||
${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
|
||||
${HW_SOURCE}
|
||||
)
|
||||
# assert and common_lib.h
|
||||
target_include_directories(rrh_gw PRIVATE ${OPENAIR_DIR}/common/utils/itti ${OPENAIR_TARGETS}/ARCH/COMMON ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ )
|
||||
|
||||
target_link_libraries(rrh_gw
|
||||
-Wl,--start-group
|
||||
UTIL LFDS
|
||||
-Wl,--end-group )
|
||||
target_link_libraries (rrh_gw rt pthread m )
|
||||
target_link_libraries (rrh_gw ${option_HW_lib} ${LIBBOOST_LIBRARIES} )
|
||||
|
||||
#Message("-- default_HW_lib=ETHERNET") # only in case of RRH
|
||||
Message("-- option_HW_lib=${option_HW_lib}")
|
||||
Message("-- HW_SOURCE=${HW_SOURCE}")
|
||||
|
||||
|
||||
|
||||
# USIM process
|
||||
#################
|
||||
#add_executable(usim
|
||||
|
||||
@@ -34,7 +34,7 @@ mkdir -p $tdir/bin $tdir/log
|
||||
|
||||
updated=$(svn st -q $OPENAIR_DIR)
|
||||
if [ "$updated" != "" ] ; then
|
||||
echo_warning "some files are not in svn: $updated"
|
||||
echo_warning "some files are not in svn:\n $updated"
|
||||
fi
|
||||
|
||||
cd $tdir
|
||||
@@ -83,5 +83,9 @@ test_compile \
|
||||
test.0120 nasmesh \
|
||||
CMakeFiles/nasmesh/nasmesh.ko $tdir/bin/nasmesh.ko
|
||||
|
||||
test_compile \
|
||||
test.0130 rrh_gw \
|
||||
rrh_gw $tdir/bin/rrh_gw
|
||||
|
||||
# write the test results into a file
|
||||
xUnit_write "$tdir/log/compilation_autotests.xml"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
set(ENABLE_VCD_FIFO False )
|
||||
set(ENABLE_ITTI False )
|
||||
set(RF_BOARD "ETHERNET")
|
||||
set(PACKAGE_NAME "\"rrh_gw\"")
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../CMakeLists.txt)
|
||||
+34
-2
@@ -75,11 +75,13 @@ Options
|
||||
Makes the UE specific parts (ue_ip, usim, nvram)
|
||||
--EPC
|
||||
Makes the EPC (MME-SPGW, HSS)
|
||||
--RRH
|
||||
Makes the RRH
|
||||
-r | --3gpp-release
|
||||
default is Rel10,
|
||||
Rel8 limits the implementation to 3GPP Release 8 version
|
||||
-w | --hardware
|
||||
EXMIMO (Default), USRP, BLADERF, None
|
||||
EXMIMO (Default), USRP, BLADERF, ETHERNET, None
|
||||
Adds this RF board support (in external packages installation and in compilation)
|
||||
--oaisim
|
||||
Makes the oaisim simulator. Hardware will be defaulted to "NONE".
|
||||
@@ -147,6 +149,10 @@ function main() {
|
||||
EPC=1
|
||||
echo_info "Will compile EPC"
|
||||
shift;;
|
||||
--RRH)
|
||||
RRH=1
|
||||
echo_info "Will compile RRH"
|
||||
shift;;
|
||||
-r | --3gpp-release)
|
||||
REL=$2
|
||||
echo_info "setting release to: $REL"
|
||||
@@ -326,7 +332,7 @@ function main() {
|
||||
# compilations \
|
||||
# at_commands at_nas_ue \
|
||||
# at_nas_ue $dbin/at_nas_ue
|
||||
|
||||
|
||||
[ "$CLEAN" = "1" ] && rm -rf $DIR/nas_sim_tools/build
|
||||
mkdir -p $DIR/nas_sim_tools/build
|
||||
cd $DIR/nas_sim_tools/build
|
||||
@@ -497,6 +503,32 @@ function main() {
|
||||
# oaisim_mme $dbin/oaisim_mme.$REL
|
||||
fi
|
||||
|
||||
# RRH compilation
|
||||
##################
|
||||
if [ "$RRH" = "1" ] ; then
|
||||
echo_info "Compiling RRH"
|
||||
if [ $HW == "ETHERNET" ] ; then
|
||||
echo_info "RF frontend for RRH is not defined. This mode is used for testing (loopback)."
|
||||
elif [ $HW != "EXMIMO" -a $HW != "OAI_USRP" -a $HW != "OAI_BLADERF" ] ; then
|
||||
echo_fatal "Hardware not defined ($HW)"
|
||||
fi
|
||||
cmake_file=$DIR/rrh_gw/CMakeLists.txt
|
||||
echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file
|
||||
echo "set(ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file
|
||||
echo "set(ENABLE_ITTI False )" >> $cmake_file
|
||||
echo "set(RF_BOARD \"${HW}\")" >> $cmake_file
|
||||
echo 'set(PACKAGE_NAME "\"rrh_gw\"")' >> $cmake_file
|
||||
echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file
|
||||
|
||||
[ "$CLEAN" = "1" ] && rm -rf $DIR/rrh_gw/build
|
||||
mkdir -p $DIR/rrh_gw/build
|
||||
cd $DIR/rrh_gw/build
|
||||
cmake ..
|
||||
compilations \
|
||||
rrh_gw rrh_gw \
|
||||
rrh_gw $dbin/rrh_gw
|
||||
fi
|
||||
|
||||
# EPC compilation
|
||||
##################
|
||||
if [ "$EPC" = "1" ] ; then
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
set(ENABLE_VCD_FIFO False )
|
||||
set(ENABLE_ITTI False )
|
||||
set(RF_BOARD "ETHERNET")
|
||||
set(PACKAGE_NAME "\"rrh_gw\"")
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)
|
||||
@@ -39,10 +39,12 @@ double get_cpu_freq_GHz(void) {
|
||||
|
||||
time_stats_t ts = {0};
|
||||
reset_meas(&ts);
|
||||
start_meas(&ts);
|
||||
ts.trials++;
|
||||
ts.in = rdtsc_oai();
|
||||
sleep(1);
|
||||
stop_meas(&ts);
|
||||
ts.diff = (rdtsc_oai()-ts.in);
|
||||
cpu_freq_GHz = (double)ts.diff/1000000000;
|
||||
printf("CPU Freq is %f \n", cpu_freq_GHz);
|
||||
return cpu_freq_GHz;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ double cpu_freq_GHz;
|
||||
typedef struct {
|
||||
|
||||
long long in;
|
||||
long long diff_now;
|
||||
long long diff;
|
||||
long long diff_now;
|
||||
long long p_time; /*!< \brief absolute process duration */
|
||||
long long diff_square; /*!< \brief process duration square */
|
||||
long long max;
|
||||
@@ -113,38 +113,31 @@ static inline void stop_meas(time_stats_t *ts)
|
||||
|
||||
if (opp_enabled) {
|
||||
long long out = rdtsc_oai();
|
||||
|
||||
ts->diff_now = (out-ts->in);
|
||||
|
||||
ts->diff += (out-ts->in);
|
||||
/// process duration is the difference between two clock points
|
||||
ts->p_time = (out-ts->in);
|
||||
ts->diff_square += (out-ts->in)*(out-ts->in);
|
||||
|
||||
if ((out-ts->in) > ts->max)
|
||||
ts->max = out-ts->in;
|
||||
|
||||
|
||||
ts->diff_now = (out-ts->in);
|
||||
|
||||
ts->diff_now = (out-ts->in);
|
||||
ts->diff += (out-ts->in);
|
||||
/// process duration is the difference between two clock points
|
||||
ts->p_time = (out-ts->in);
|
||||
ts->diff_square += (out-ts->in)*(out-ts->in);
|
||||
|
||||
if ((out-ts->in) > ts->max)
|
||||
ts->max = out-ts->in;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static inline void reset_meas(time_stats_t *ts)
|
||||
{
|
||||
static inline void reset_meas(time_stats_t *ts) {
|
||||
|
||||
static int cpu_freq_set=0;
|
||||
|
||||
if (opp_enabled) {
|
||||
ts->trials=0;
|
||||
ts->diff_now=0;
|
||||
ts->diff=0;
|
||||
ts->p_time=0;
|
||||
ts->diff_square=0;
|
||||
ts->max=0;
|
||||
|
||||
if (cpu_freq_set == 0) {
|
||||
cpu_freq_set = 1;
|
||||
get_cpu_freq_GHz();
|
||||
printf("CPU Freq is %f \n", cpu_freq_GHz);
|
||||
}
|
||||
}
|
||||
ts->trials=0;
|
||||
ts->diff=0;
|
||||
ts->diff_now=0;
|
||||
ts->p_time=0;
|
||||
ts->diff_square=0;
|
||||
ts->max=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -398,7 +398,15 @@ int logInit (void)
|
||||
g_log->log_component[SCTP].fd = 0;
|
||||
g_log->log_component[SCTP].filelog = 0;
|
||||
g_log->log_component[SCTP].filelog_name = "";
|
||||
|
||||
|
||||
g_log->log_component[RRH].name = "RRH";
|
||||
g_log->log_component[RRH].level = LOG_EMERG;
|
||||
g_log->log_component[RRH].flag = LOG_MED;
|
||||
g_log->log_component[RRH].interval = 1;
|
||||
g_log->log_component[RRH].fd = 0;
|
||||
g_log->log_component[RRH].filelog = 0;
|
||||
g_log->log_component[RRH].filelog_name = "";
|
||||
|
||||
g_log->level2string[LOG_EMERG] = "G"; //EMERG
|
||||
g_log->level2string[LOG_ALERT] = "A"; // ALERT
|
||||
g_log->level2string[LOG_CRIT] = "C"; // CRITIC
|
||||
|
||||
@@ -267,6 +267,7 @@ typedef enum {
|
||||
TMR,
|
||||
USIM,
|
||||
LOCALIZE,
|
||||
RRH,
|
||||
MAX_LOG_COMPONENTS,
|
||||
}
|
||||
comp_name_t;
|
||||
|
||||
@@ -77,6 +77,8 @@ struct vcd_module_s {
|
||||
const char* eurecomVariablesNames[] = {
|
||||
"frame_number_TX_eNB",
|
||||
"frame_number_RX_eNB",
|
||||
"runtime_TX_eNB",
|
||||
"runtime_RX_eNB",
|
||||
"frame_number_TX_UE",
|
||||
"frame_number_RX_UE",
|
||||
"slot_number_TX_UE",
|
||||
@@ -94,6 +96,13 @@ const char* eurecomVariablesNames[] = {
|
||||
"rxcnt",
|
||||
"trx_ts",
|
||||
"trx_tst",
|
||||
"tx_ts",
|
||||
"rx_ts",
|
||||
"hw_cnt_rx",
|
||||
"lhw_cnt_rx",
|
||||
"hw_cnt_tx",
|
||||
"lhw_cnt_tx",
|
||||
"pck_rx",
|
||||
"dummy_dump",
|
||||
"itti_send_msg",
|
||||
"itti_poll_msg",
|
||||
@@ -133,6 +142,15 @@ const char* eurecomFunctionsNames[] = {
|
||||
"ue_thread_tx",
|
||||
"ue_thread_rx",
|
||||
|
||||
/* RRH signals */
|
||||
"eNB_tx",
|
||||
"eNB_rx",
|
||||
"eNB_trx",
|
||||
"eNB_tm",
|
||||
"eNB_rx_sleep",
|
||||
"eNB_tx_sleep",
|
||||
"eNB_proc_sleep",
|
||||
|
||||
/* PHY signals */
|
||||
"ue_synch",
|
||||
"ue_slot_fep",
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_ENB = 0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RX_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX_UE,
|
||||
@@ -66,6 +68,13 @@ typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RXCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_POLL_MSG,
|
||||
@@ -107,6 +116,16 @@ typedef enum {
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX,
|
||||
|
||||
/* RRH signals */
|
||||
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TM,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_SLEEP,
|
||||
|
||||
/* PHY signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP,
|
||||
|
||||
@@ -132,7 +132,7 @@ int trx_brf_end(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int openair0_device_brf_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
//int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
int status;
|
||||
@@ -263,15 +263,27 @@ int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cf
|
||||
return 0;
|
||||
}
|
||||
|
||||
void brf_error(int status) {
|
||||
int brf_error(int status) {
|
||||
|
||||
exit(-1);
|
||||
//return 1; // or status error code
|
||||
}
|
||||
|
||||
int openair0_stop(int card) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int openair0_print_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int openair0_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int dummy) {
|
||||
return 0;
|
||||
|
||||
@@ -78,4 +78,4 @@ typedef struct {
|
||||
* func prototypes
|
||||
*/
|
||||
|
||||
void brf_error(int status);
|
||||
int brf_error(int status);
|
||||
|
||||
@@ -26,16 +26,23 @@
|
||||
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>
|
||||
|
||||
typedef int64_t openair0_timestamp;
|
||||
typedef volatile int64_t openair0_vtimestamp;
|
||||
typedef struct openair0_device_t openair0_device;
|
||||
/* structrue holds the parameters to configure USRP devices
|
||||
*/
|
||||
@@ -56,10 +63,18 @@ typedef struct {
|
||||
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)
|
||||
@@ -84,9 +99,14 @@ typedef struct {
|
||||
//! 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 {
|
||||
@@ -98,10 +118,42 @@ typedef struct {
|
||||
|
||||
|
||||
|
||||
/*!\brief device type */
|
||||
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 type */
|
||||
typedef enum {
|
||||
MIN_FUNC_TYPE = 0,
|
||||
BBU_FUNC,
|
||||
RRH_FUNC,
|
||||
MAX_FUNC_TYPE
|
||||
|
||||
}func_type_t;
|
||||
|
||||
struct openair0_device_t {
|
||||
/* Module ID of this device */
|
||||
int Mod_id;
|
||||
|
||||
/* Type of this device */
|
||||
func_type_t func_type;
|
||||
|
||||
/* Type of this device */
|
||||
dev_type_t type;
|
||||
|
||||
/* RF frontend parameters set by application */
|
||||
openair0_config_t openair0_cfg;
|
||||
|
||||
@@ -113,11 +165,20 @@ struct openair0_device_t {
|
||||
/* Called to start the transceiver. Return 0 if OK, < 0 if error */
|
||||
int (*trx_start_func)(openair0_device *device);
|
||||
|
||||
/* Called to initiate transceiver threads */
|
||||
void (*trx_thread_func)(openair0_device *device, unsigned int rt_period, uint8_t RT_flag,uint8_t NRT_flag);
|
||||
|
||||
/* Called to request connection from the transceiver/RRH. Return 0 if OK, < 0 if error */
|
||||
int (*trx_request_func)(openair0_device *device);
|
||||
|
||||
/* Called to reply back to connection state to eNB/BBU. Return 0 if OK, < 0 if error */
|
||||
int (*trx_reply_func)(openair0_device *openair0);
|
||||
|
||||
/* 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);
|
||||
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
|
||||
@@ -130,7 +191,19 @@ 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);
|
||||
|
||||
/*! \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);
|
||||
|
||||
/* Terminate operation of the transceiver -- free all associated resources */
|
||||
void (*trx_end_func)(openair0_device *device);
|
||||
@@ -142,15 +215,33 @@ 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 exmimo_dump_config);
|
||||
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);
|
||||
|
||||
int openair0_stop(int card);
|
||||
/* return 0 if OK */
|
||||
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
openair0_timestamp get_usrp_time(openair0_device *device);
|
||||
|
||||
//EXMIMO
|
||||
//int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
//USPRP
|
||||
//int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
//BLADERF
|
||||
//int openair0_dev_init_bladerf(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
|
||||
//ETHERNET
|
||||
int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
|
||||
|
||||
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);
|
||||
|
||||
int openair0_print_stats(openair0_device* device);
|
||||
|
||||
int openair0_reset_stats(openair0_device* device);
|
||||
|
||||
int openair0_stop(int card);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
/*! \fileethernet_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,203 +50,361 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "ethernet_lib.h"
|
||||
|
||||
#define DEFAULT_IF "eth0"
|
||||
#define BUF_SIZ 8960 /*Jumbo frame size*/
|
||||
#define BUF_SIZ 8960 /*Jumbo frame size*/
|
||||
#define MAX_INST 4
|
||||
|
||||
int sockfd[MAX_INST];
|
||||
struct sockaddr_in dest_addr[MAX_INST];
|
||||
//int sockfd[MAX_INST];
|
||||
int num_devices = 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)
|
||||
{
|
||||
/* Initialization of UDP Socket to communicate with one destination */
|
||||
int ethernet_socket_init(openair0_device *device) {
|
||||
|
||||
/**PDF: To be passed by input argument*/
|
||||
// DEST_port = 32000;
|
||||
struct sockaddr_in *dest = &dest_addr[Mod_id];
|
||||
int i = 0;
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
|
||||
// struct sockaddr_in *dest = &dest_addr[Mod_id];
|
||||
char str[INET_ADDRSTRLEN];
|
||||
|
||||
const char *dest_ip;
|
||||
int dest_port;
|
||||
|
||||
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);
|
||||
/* initialize destination address */
|
||||
for (i=0; i< MAX_INST; i++)
|
||||
bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
|
||||
|
||||
inet_ntop(AF_INET, &(dest->sin_addr), str, INET_ADDRSTRLEN);
|
||||
printf("Connecting to %s:%d\n",str,ntohs(dest->sin_port));
|
||||
// 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
void ethernet_socket_opt (openair0_device *device){
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id=device->Mod_id;
|
||||
|
||||
int sndbuf_size=0, rcvbuf_size=0;
|
||||
socklen_t optlen;
|
||||
/* chang the MTU of the eth interface */
|
||||
struct ifreq ifr;
|
||||
|
||||
optlen = sizeof(int);
|
||||
|
||||
if (getsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_SNDBUF,
|
||||
&sndbuf_size,&optlen))
|
||||
printf("error:getsockopt()\n");
|
||||
|
||||
if (getsockopt(eth->sockfd[Mod_id],
|
||||
SOL_SOCKET,
|
||||
SO_RCVBUF,
|
||||
&rcvbuf_size,&optlen))
|
||||
printf("error:getsockopt()\n");
|
||||
|
||||
printf( "sndbuf_size= %d bytes rcvbuf_size= %d bytes\n", sndbuf_size,
|
||||
rcvbuf_size);
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
//iap->ifa_name is bond1:xx
|
||||
strncpy(ifr.ifr_name, DEFAULT_IF, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_mtu = device->openair0_cfg.samples_per_packet*5;
|
||||
if (ioctl(eth->sockfd[Mod_id], SIOCSIFMTU, (caddr_t)&ifr) < 0 )
|
||||
perror ("Can't set the MTU");
|
||||
else
|
||||
printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int trx_eth_request(openair0_device *device) {
|
||||
|
||||
int Mod_id = device->Mod_id;
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
void *msg;
|
||||
ssize_t msg_len;
|
||||
|
||||
|
||||
/* send to RRH (server) required configuration parameters:
|
||||
-number of downlink RBs (so that frame/packet size can be set accordingly)
|
||||
-rx_num_0channels
|
||||
-tx_num_channels
|
||||
-rx_freq
|
||||
-tx_freq
|
||||
-rxg_mode[4]
|
||||
-rx_gain
|
||||
-tx_gain
|
||||
-rx_bw
|
||||
-tx_bw
|
||||
-autocal */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ethernet_write_data(int Mod_id, openair0_timestamp timestamp, const void **buff, int antenna_id, int nsamps)
|
||||
{
|
||||
int trx_eth_reply(openair0_device *device) {
|
||||
|
||||
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));
|
||||
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);
|
||||
|
||||
/* receive from client (lte-softmodem) */
|
||||
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;
|
||||
//ethernet_socket_opt (device);
|
||||
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 1;
|
||||
}
|
||||
|
||||
|
||||
int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id) {
|
||||
|
||||
int n_written;
|
||||
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;
|
||||
|
||||
/* buff[antenna_id] 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[antenna_id]-header_size); // (void*)((unsigned char *)buff[antenna_id]-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));
|
||||
//printf("temp0=%d temp=%d\n",temp0,temp1);
|
||||
//char str[INET_ADDRSTRLEN];
|
||||
|
||||
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) {
|
||||
|
||||
*(int16_t *)(buff2 + sizeof(int16_t))=1+(antenna_id<<1);
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
|
||||
|
||||
//inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
|
||||
//printf("[RRH]write mod_%d %d to %s:%d, len %d, buff %p antenna %d\n",
|
||||
//Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port),(nsamps<<2)+header_size, buff2, antenna_id);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* printf("Buffer head TX: nu=%d an_id=%d ts%d byte_send=%d \n", *(int16_t *)buff2,
|
||||
*(int16_t *)(buff2 + sizeof(int16_t)),
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
|
||||
n_written>>2);*/
|
||||
|
||||
/* tx buffer values restored */
|
||||
*(int32_t *)buff2 = temp0;
|
||||
*(openair0_timestamp *)(buff2+2*sizeof(int16_t)) = temp1;
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
|
||||
//printf("-----------------temp0=%d temp=%d\n",*(int32_t *)buff2,*(openair0_timestamp *)(buff2 + sizeof(int32_t)));
|
||||
return n_written;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int antenna_id, int nsamps)
|
||||
{
|
||||
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id) {
|
||||
|
||||
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];
|
||||
uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
|
||||
|
||||
//mesg[0] = 0+(antenna_id<<1);
|
||||
//mesg[1] = nsamps;
|
||||
|
||||
inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
|
||||
|
||||
/* buff[antenna_id] 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[antenna_id]-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));
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
int Mod_id = device->Mod_id;
|
||||
|
||||
inet_ntop(AF_INET, &(eth->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]);
|
||||
// printf("requesting %d samples from (%s:%d)\n",nsamps,str,ntohs(eth->dest_addr[Mod_id].sin_port));
|
||||
|
||||
bytes_received=0;
|
||||
block_cnt=0;
|
||||
|
||||
while(bytes_received < (int)((nsamps<<2))) {
|
||||
//printf("requesting %d bytes\n",(nsamps<<2));
|
||||
ret=recvfrom(sockfd[Mod_id],
|
||||
ret=recvfrom(eth->sockfd[Mod_id],
|
||||
buff2+bytes_received,
|
||||
(nsamps<<2)+sizeof(openair0_timestamp)-bytes_received,
|
||||
(nsamps<<2)+header_size-bytes_received,
|
||||
0,//MSG_DONTWAIT,
|
||||
(struct sockaddr *)&dest_addr[Mod_id],
|
||||
&dest_addr_len[Mod_id]);
|
||||
(struct sockaddr *)ð->dest_addr[Mod_id],
|
||||
(socklen_t *)&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));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//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;
|
||||
/*
|
||||
printf("Buffer head RX: nu=%d an_id=%d ts%d byte_recv=%d\n", *(int16_t *)buff2,
|
||||
*(int16_t *)(buff2 + sizeof(int16_t)),
|
||||
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
|
||||
ret>>2);*/
|
||||
|
||||
/* 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;
|
||||
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
|
||||
|
||||
return nsamps;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int trx_eth_start(openair0_device *openair0)
|
||||
{
|
||||
int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int antenna_id, int flags) {
|
||||
|
||||
return ethernet_write_data(device,timestamp,buff,nsamps,antenna_id);
|
||||
}
|
||||
|
||||
int16_t mesg[2];
|
||||
int Mod_id;
|
||||
|
||||
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);
|
||||
|
||||
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]);
|
||||
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int antenna_id) {
|
||||
|
||||
return(ethernet_read_data(device,ptimestamp,buff,nsamps,antenna_id));
|
||||
|
||||
}
|
||||
|
||||
int openair0_stop(int card) {
|
||||
|
||||
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 openair0_print_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int openair0_reset_stats(openair0_device* device) {
|
||||
|
||||
int openair0_stop(int dummy) {
|
||||
return(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void trx_eth_end(openair0_device *device) {
|
||||
// close all the sockets
|
||||
|
||||
|
||||
}
|
||||
|
||||
int num_devices = 0;
|
||||
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
int openair0_dev_init_eth(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;
|
||||
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;
|
||||
|
||||
printf("ETHERNET: Initializing openair0_device for %s ...\n", ((device->func_type == BBU_FUNC) ? "BBU": "RRH"));
|
||||
device->Mod_id = num_devices++;
|
||||
device->trx_request_func = trx_eth_request;
|
||||
device->trx_reply_func = trx_eth_reply;
|
||||
device->trx_end_func = trx_eth_end;
|
||||
device->trx_read_func = trx_eth_read;
|
||||
device->trx_write_func = trx_eth_write;
|
||||
|
||||
memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
|
||||
|
||||
if (ethernet_socket_init(device)!=0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
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,75 @@
|
||||
#include <net/if.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port);
|
||||
|
||||
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[4];
|
||||
struct sockaddr_in dest_addr[4];
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* packet's timestamp */
|
||||
openair0_timestamp timestamp;
|
||||
/* variable declared for alignment purposes (sample size=32 bit) */
|
||||
int16_t not_used;
|
||||
/* antenna port used to resynchronize*/
|
||||
int16_t antenna_id;
|
||||
} header_t;
|
||||
|
||||
|
||||
|
||||
int ethernet_socket_init(openair0_device *device);
|
||||
|
||||
int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id);
|
||||
|
||||
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id);
|
||||
|
||||
void ethernet_socket_opt (openair0_device *device);
|
||||
|
||||
@@ -247,6 +247,7 @@ 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_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
// Initialize card
|
||||
|
||||
@@ -44,8 +44,10 @@
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "common_lib.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -121,7 +123,7 @@ static void trx_usrp_end(openair0_device *device)
|
||||
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,6 +140,8 @@ 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)
|
||||
@@ -195,7 +199,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 dummy) {
|
||||
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg, int dummy) {
|
||||
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
|
||||
@@ -237,7 +241,17 @@ int openair0_stop(int card) {
|
||||
return(0);
|
||||
|
||||
}
|
||||
int openair0_print_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
int openair0_reset_stats(openair0_device* device) {
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
//int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
uhd::set_thread_priority_safe(1.0);
|
||||
@@ -376,7 +390,7 @@ int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cf
|
||||
device->trx_end_func = trx_usrp_end;
|
||||
device->trx_read_func = trx_usrp_read;
|
||||
device->trx_write_func = trx_usrp_write;
|
||||
|
||||
|
||||
s->sample_rate = openair0_cfg[0].sample_rate;
|
||||
// TODO:
|
||||
// init tx_forward_nsamps based usrp_time_offset ex
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
/*******************************************************************************
|
||||
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 UE_transport_IQ.c
|
||||
* \brief UE transport IQ sampels
|
||||
* \author Katerina Trilyraki, Navid Nikaein, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning very experimental
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "PHY/defs.h"
|
||||
#include "rrh_gw.h"
|
||||
#include "rrh_gw_externs.h"
|
||||
|
||||
#define START_CMD 1
|
||||
#define RRH_UE_PORT 51000
|
||||
#define RRH_UE_DEST_IP "127.0.0.1"
|
||||
#define PRINTF_PERIOD 3750
|
||||
|
||||
/******************************************************************************
|
||||
** FUNCTION PROTOTYPES **
|
||||
******************************************************************************/
|
||||
void *rrh_proc_UE_thread(void *);
|
||||
void *rrh_UE_thread(void *);
|
||||
void *rrh_UE_rx_thread(void *);
|
||||
void *rrh_UE_tx_thread(void *);
|
||||
|
||||
|
||||
|
||||
openair0_timestamp timestamp_UE_tx[4]= {0,0,0,0},timestamp_UE_rx[4]= {0,0,0,0};
|
||||
openair0_timestamp nrt_UE_counter[4]= {0,0,0,0};
|
||||
|
||||
pthread_t main_rrh_UE_thread,main_rrh_proc_UE_thread;
|
||||
pthread_attr_t attr, attr_proc;
|
||||
struct sched_param sched_param_rrh, sched_param_rrh_proc;
|
||||
pthread_cond_t sync_UE_cond[4];
|
||||
pthread_mutex_t sync_UE_mutex[4];
|
||||
|
||||
int32_t overflow_rx_buffer_UE[4]= {0,0,0,0};
|
||||
int32_t nsamps_UE[4]= {0,0,0,0};
|
||||
int32_t UE_tx_started=0,UE_rx_started=0;
|
||||
int32_t RT_flag_UE=0, NRT_flag_UE=1;
|
||||
int32_t counter_UE_rx[4]= {0,0,0,0};
|
||||
int32_t counter_UE_tx[4]= {0,0,0,0};
|
||||
int32_t **tx_buffer_UE, **rx_buffer_UE;
|
||||
|
||||
int sync_UE_rx[4]= {-1,-1,-1,-1};
|
||||
void *rrh_UE_thread_status;
|
||||
|
||||
|
||||
void *rx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx
|
||||
void *tx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx
|
||||
|
||||
/*! \fn void create_UE_trx_threads( openair0_device *dev_ue, uint8_t RT_flag,uint8_t NRT_flag)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void create_UE_trx_threads( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) {
|
||||
|
||||
int i;
|
||||
int error_code_UE, error_code_proc_UE;
|
||||
void *tmp;
|
||||
|
||||
RT_flag_UE=RT_flag;
|
||||
NRT_flag_UE=NRT_flag;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
pthread_attr_init(&attr_proc);
|
||||
sched_param_rrh_proc.sched_priority = sched_get_priority_max(SCHED_FIFO-1);
|
||||
|
||||
pthread_attr_setschedparam(&attr,&sched_param_rrh);
|
||||
pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
|
||||
pthread_attr_setschedparam(&attr_proc,&sched_param_rrh_proc);
|
||||
pthread_attr_setschedpolicy(&attr_proc,SCHED_FIFO-1);
|
||||
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
pthread_mutex_init(&sync_UE_mutex[i],NULL);
|
||||
pthread_cond_init(&sync_UE_cond[i],NULL);
|
||||
}
|
||||
|
||||
error_code_UE = pthread_create(&main_rrh_UE_thread, &attr, rrh_UE_thread, (void *)dev_ue);
|
||||
error_code_proc_UE = pthread_create(&main_rrh_proc_UE_thread, &attr_proc, rrh_proc_UE_thread, (void *)dev_ue);
|
||||
|
||||
if (error_code_UE) {
|
||||
printf("Error while creating UE thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (error_code_proc_UE) {
|
||||
printf("Error while creating UE proc thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void *rrh_proc_UE_thread((void *)dev_ue)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_proc_UE_thread(void * arg) {
|
||||
|
||||
int antenna_index,i;
|
||||
openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0;
|
||||
struct timespec time_req, time_rem;
|
||||
int16_t *txp,*rxp;
|
||||
unsigned int samples_per_frame=0;
|
||||
rrh_module_t *dev=(rrh_module_t *)arg;
|
||||
|
||||
samples_per_frame= dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
AssertFatal(samples_per_frame <=0, "invalide samples_per_frame !%u\n",samples_per_frame);
|
||||
|
||||
time_req.tv_sec = 0;
|
||||
time_req.tv_nsec = 1000;
|
||||
|
||||
while (rrh_exit==0) {
|
||||
//wait until some data has been copied
|
||||
for (antenna_index=0; antenna_index<4; antenna_index++) {
|
||||
if (sync_UE_rx[antenna_index]==0) {
|
||||
if (!UE_tx_started) {
|
||||
UE_tx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data
|
||||
if (RT_flag_UE==1) {
|
||||
last_hw_counter=hw_counter;
|
||||
}
|
||||
} else {
|
||||
if (RT_flag_UE==1) {
|
||||
if (hw_counter > last_hw_counter+1) {
|
||||
printf("L1");
|
||||
// goto end_copy_UE;
|
||||
} else {
|
||||
while (hw_counter < last_hw_counter+1)
|
||||
nanosleep(&time_req,&time_rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
truncated_timestamp = timestamp_UE_tx[antenna_index]%(samples_per_frame);
|
||||
truncated_timestamp_final = (timestamp_UE_tx[antenna_index]+nsamps_UE[antenna_index])%samples_per_frame;
|
||||
|
||||
if ((truncated_timestamp + nsamps_UE[antenna_index]) > samples_per_frame) {
|
||||
if ((timestamp_eNB_rx[antenna_index]%samples_per_frame < nsamps_UE[antenna_index]) && (eNB_rx_started==1)) {
|
||||
overflow_rx_buffer_eNB[antenna_index]++;
|
||||
printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp);
|
||||
|
||||
if (NRT_flag_UE==1) {
|
||||
while ((timestamp_eNB_rx[antenna_index]%samples_per_frame) < nsamps_UE[antenna_index])
|
||||
nanosleep(&time_req,&time_rem);
|
||||
}
|
||||
}
|
||||
|
||||
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp];
|
||||
txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp];
|
||||
|
||||
for (i=0; i<(samples_per_frame<<1)-(truncated_timestamp<<1); i++) {
|
||||
rxp[i] = txp[i]>>6;
|
||||
}
|
||||
|
||||
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][0];
|
||||
txp = (int16_t*)&tx_buffer_UE[antenna_index][0];
|
||||
|
||||
for (i=0; i<nsamps_eNB[antenna_index]-(samples_per_frame)+(truncated_timestamp); i++) {
|
||||
rxp[i] = txp[i]>>6;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (((truncated_timestamp < (timestamp_eNB_rx[antenna_index]%samples_per_frame)) &&
|
||||
(truncated_timestamp_final > (timestamp_eNB_rx[antenna_index]%samples_per_frame))) &&
|
||||
(eNB_rx_started==1)) {
|
||||
overflow_rx_buffer_eNB[antenna_index]++;
|
||||
printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp);
|
||||
|
||||
if (NRT_flag_UE==1) {
|
||||
while (truncated_timestamp_final > timestamp_eNB_rx[antenna_index]%samples_per_frame)
|
||||
nanosleep(&time_req,&time_rem);
|
||||
}
|
||||
}
|
||||
|
||||
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp];
|
||||
txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp];
|
||||
|
||||
for (i=0; i<(nsamps_eNB[antenna_index]); i++) {
|
||||
rxp[i] =txp[i]>>6;
|
||||
}
|
||||
|
||||
}
|
||||
//end_copy_UE :
|
||||
last_hw_counter=hw_counter;
|
||||
pthread_mutex_lock(&sync_UE_mutex[antenna_index]);
|
||||
sync_UE_rx[antenna_index]--;
|
||||
pthread_mutex_unlock(&sync_UE_mutex[antenna_index]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*! \fn void *rrh_UE_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_UE_thread(void *arg) {
|
||||
|
||||
rrh_module_t *dev=(rrh_module_t *)arg;
|
||||
|
||||
struct sched_param sched_param_UE_rx, sched_param_UE_tx;
|
||||
int16_t i,cmd; //,nsamps,antenna_index;
|
||||
ssize_t bytes_received;
|
||||
struct timespec time_req_1us, time_rem_1us;
|
||||
pthread_t UE_rx_thread, UE_tx_thread;
|
||||
pthread_attr_t attr_UE_rx, attr_UE_tx;
|
||||
int error_code_UE_rx, error_code_UE_tx;
|
||||
void *tmp;
|
||||
unsigned int samples_per_frame=0;
|
||||
|
||||
samples_per_frame= dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
time_req_1us.tv_sec = 0;
|
||||
time_req_1us.tv_nsec = 1000;
|
||||
|
||||
while (rrh_exit==0) {
|
||||
|
||||
cmd=dev->eth_dev.trx_reply_func(&dev->eth_dev);
|
||||
|
||||
/* allocate memory for TX/RX buffers */
|
||||
rx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.rx_num_channels*sizeof(int32_t*));
|
||||
tx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.tx_num_channels*sizeof(int32_t*));
|
||||
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.rx_num_channels; i++) {
|
||||
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4));
|
||||
memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4));
|
||||
rx_buffer_UE[i]=(tmp+4*sizeof(int32_t));
|
||||
}
|
||||
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++) {
|
||||
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4));
|
||||
memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4));
|
||||
tx_buffer_UE[i]=(tmp+4*sizeof(int32_t));
|
||||
}
|
||||
|
||||
printf("Client %s:%d is connected (DL_RB=%d) rt=%d|%d. \n" , dev->eth_dev.openair0_cfg.remote_ip,
|
||||
dev->eth_dev.openair0_cfg.remote_port,
|
||||
dev->eth_dev.openair0_cfg.num_rb_dl,
|
||||
dev->eth_dev.openair0_cfg.rx_num_channels,
|
||||
dev->eth_dev.openair0_cfg.tx_num_channels);
|
||||
|
||||
if (cmd==START_CMD) {
|
||||
|
||||
pthread_attr_init(&attr_UE_rx);
|
||||
pthread_attr_init(&attr_UE_tx);
|
||||
sched_param_UE_rx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_param_UE_tx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
pthread_attr_setschedparam(&attr_UE_rx,&sched_param_UE_rx);
|
||||
pthread_attr_setschedparam(&attr_UE_tx,&sched_param_UE_tx);
|
||||
pthread_attr_setschedpolicy(&attr_UE_rx,SCHED_FIFO);
|
||||
pthread_attr_setschedpolicy(&attr_UE_tx,SCHED_FIFO);
|
||||
|
||||
error_code_UE_rx = pthread_create(&UE_rx_thread, &attr_UE_rx, rrh_UE_rx_thread, (void *)&dev);
|
||||
error_code_UE_tx = pthread_create(&UE_tx_thread, &attr_UE_tx, rrh_UE_tx_thread, (void *)&dev);
|
||||
|
||||
if (error_code_UE_rx) {
|
||||
printf("Error while creating UE RX thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (error_code_UE_tx) {
|
||||
printf("Error while creating UE TX thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while (rrh_exit==0)
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rrh_UE_thread_status = 0;
|
||||
pthread_exit(&rrh_UE_thread_status);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void *rrh_UE_rx_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_UE_rx_thread(void *arg) {
|
||||
|
||||
rrh_module_t *dev = (rrh_module_t *)arg;
|
||||
struct timespec time0,time1,time2;
|
||||
struct timespec time_req_1us, time_rem_1us;
|
||||
ssize_t bytes_sent;
|
||||
int antenna_index, nsamps;
|
||||
int trace_cnt=0;
|
||||
unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0;
|
||||
unsigned int samples_per_frame=0;
|
||||
openair0_timestamp temp, last_hw_counter=0;
|
||||
|
||||
antenna_index = 0;
|
||||
nsamps = dev->eth_dev.openair0_cfg.samples_per_packet;
|
||||
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
|
||||
while (rrh_exit == 0) {
|
||||
if (!UE_rx_started) {
|
||||
UE_rx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data
|
||||
|
||||
if (RT_flag_UE==1) {
|
||||
last_hw_counter=hw_counter;
|
||||
}
|
||||
} else {
|
||||
if (RT_flag_UE==1) {
|
||||
if (hw_counter > last_hw_counter+1) {
|
||||
printf("L1");
|
||||
//goto end_copy_UE;
|
||||
} else {
|
||||
while (hw_counter < last_hw_counter+1)
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time1);
|
||||
|
||||
// send return
|
||||
|
||||
if ((timestamp_UE_rx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit
|
||||
if (((timestamp_eNB_tx[antenna_index]%(samples_per_frame)) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame))) && (eNB_tx_started==1)) {
|
||||
printf("UE underflow wraparound timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",
|
||||
(int)(timestamp_UE_rx[antenna_index]%(samples_per_frame)),
|
||||
(int)(timestamp_eNB_tx[antenna_index]%samples_per_frame));
|
||||
|
||||
if (NRT_flag_UE==1) {
|
||||
while ((timestamp_eNB_tx[antenna_index]%samples_per_frame) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame)))
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
}
|
||||
}
|
||||
|
||||
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)];
|
||||
if ((bytes_sent =dev->eth_dev.trx_write_func (dev,
|
||||
timestamp_UE_rx[antenna_index],
|
||||
rx_ue,
|
||||
( samples_per_frame- (timestamp_eNB_rx[antenna_index]%(samples_per_frame)) ),
|
||||
antenna_index,
|
||||
0))<0)
|
||||
perror("RRH UE : sendto for RX");
|
||||
|
||||
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][3];
|
||||
if ((bytes_sent =dev->eth_dev.trx_write_func (dev,
|
||||
timestamp_UE_rx[antenna_index],
|
||||
rx_ue,
|
||||
(nsamps - samples_per_frame + (timestamp_eNB_rx[antenna_index]%(samples_per_frame))),
|
||||
antenna_index,
|
||||
0))<0)
|
||||
perror("RRH UE : sendto for RX");
|
||||
|
||||
} else {
|
||||
if (((timestamp_UE_rx[antenna_index]%samples_per_frame)< timestamp_eNB_tx[antenna_index]%samples_per_frame) &&
|
||||
(((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) &&
|
||||
(eNB_tx_started==1) ) {
|
||||
printf("UE underflow timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",
|
||||
(int)(timestamp_UE_rx[antenna_index]%samples_per_frame),
|
||||
(int)(timestamp_eNB_tx[antenna_index]%samples_per_frame));
|
||||
|
||||
if (NRT_flag_UE==1) {
|
||||
while (((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) {
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)];
|
||||
if ((bytes_sent = dev->eth_dev.trx_write_func (dev,
|
||||
timestamp_UE_rx[antenna_index],
|
||||
rx_ue,
|
||||
nsamps,
|
||||
antenna_index,
|
||||
0))<0)
|
||||
perror("RRH UE thread: sendto for RX");
|
||||
}
|
||||
|
||||
timestamp_UE_rx[antenna_index]+=nsamps;
|
||||
last_hw_counter=hw_counter;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time2);
|
||||
|
||||
if (trace_cnt++ > 10) {
|
||||
total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec);
|
||||
|
||||
if (total_rx_time < 0) total_rx_time=1000000000-total_rx_time;
|
||||
|
||||
if ((total_rx_time > 0) && (total_rx_time < 1000000000)) {
|
||||
trial++;
|
||||
|
||||
if (total_rx_time < min_rx_time)
|
||||
min_rx_time = total_rx_time;
|
||||
|
||||
if (total_rx_time > max_rx_time)
|
||||
max_rx_time = total_rx_time;
|
||||
|
||||
average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1);
|
||||
}
|
||||
|
||||
if (s_period++ == PRINTF_PERIOD) {
|
||||
s_period=0;
|
||||
printf("Average UE RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time);
|
||||
|
||||
}
|
||||
|
||||
//printf("RX: t1 %llu (time from last send), t2 %llu (sendto of %lu bytes) total time : %llu\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), (long long unsigned int)(time2.tv_nsec - time1.tv_nsec),
|
||||
// (nsamps<<2)+sizeof(openair0_timestamp),(long long unsigned int)(time2.tv_nsec - time0.tv_nsec));
|
||||
|
||||
}
|
||||
|
||||
memcpy(&time0,&time2,sizeof(struct timespec));
|
||||
|
||||
} //while (UE_exit==0)
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void *rrh_UE_tx_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_UE_tx_thread(void *arg) {
|
||||
|
||||
struct timespec time0a,time0,time1,time2;
|
||||
struct timespec time_req_1us, time_rem_1us;
|
||||
|
||||
|
||||
rrh_module_t *dev = (rrh_module_t *)arg;
|
||||
ssize_t bytes_received;
|
||||
int antenna_index, nsamps;
|
||||
int trace_cnt=0;
|
||||
unsigned int samples_per_frame=0;
|
||||
|
||||
antenna_index = 0;
|
||||
nsamps = dev->eth_dev.openair0_cfg.samples_per_packet;
|
||||
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
|
||||
|
||||
while (rrh_exit == 0) {
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time0a);
|
||||
|
||||
bytes_received = dev->eth_dev.trx_read_func(dev,
|
||||
×tamp_UE_tx[antenna_index],
|
||||
tx_ue,
|
||||
nsamps,
|
||||
antenna_index);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time1);
|
||||
|
||||
if (NRT_flag_UE==1) {
|
||||
nrt_UE_counter[antenna_index]++;
|
||||
}
|
||||
printf(" first part size: %d second part size: %d idx=%d \n",
|
||||
(int32_t)(((samples_per_frame)<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)),
|
||||
(nsamps<<2)-((samples_per_frame)<<2)+((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2),
|
||||
timestamp_UE_tx[antenna_index]%(samples_per_frame));
|
||||
if ((timestamp_UE_tx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit
|
||||
memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)],(void*)(tx_ue[antenna_index]),
|
||||
(samples_per_frame<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2));
|
||||
|
||||
memcpy(&tx_buffer_UE[antenna_index][0], (void*)(tx_ue[antenna_index]+(samples_per_frame*4)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)),
|
||||
(nsamps<<2)-((samples_per_frame-(timestamp_UE_tx[antenna_index]%(samples_per_frame)))<<2));
|
||||
//printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2));
|
||||
} else {
|
||||
memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)], (void*)(tx_ue[antenna_index]),(nsamps<<2));
|
||||
}
|
||||
|
||||
while (sync_UE_rx[antenna_index]==0)
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
|
||||
pthread_mutex_lock(&sync_UE_mutex[antenna_index]);
|
||||
sync_UE_rx[antenna_index]++;
|
||||
|
||||
if (!sync_UE_rx[antenna_index]) {
|
||||
counter_UE_tx[antenna_index]=(counter_UE_tx[antenna_index]+nsamps)%samples_per_frame;
|
||||
nsamps_UE[antenna_index]=nsamps;
|
||||
} else {
|
||||
printf("rrh_eNB_proc thread is busy, will exit\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&sync_UE_mutex[antenna_index]);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time2);
|
||||
|
||||
memcpy(&time0,&time2,sizeof(struct timespec));
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
/*******************************************************************************
|
||||
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 eNB_transport_IQ.c
|
||||
* \brief eNB transport IQ sampels
|
||||
* \author Katerina Trilyraki, Navid Nikaein, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning very experimental
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "PHY/defs.h"
|
||||
#include "rrh_gw.h"
|
||||
#include "rrh_gw_externs.h"
|
||||
#include "rt_wrapper.h"
|
||||
|
||||
#define RRH_eNB_PORT 50000
|
||||
#define RRH_eNB_DEST_IP "192.168.12.31"
|
||||
#define PRINTF_PERIOD 3750
|
||||
#define HEADER_SIZE ((sizeof(int32_t) + sizeof(openair0_timestamp))>>2)
|
||||
//#undef LOWLATENCY
|
||||
/******************************************************************************
|
||||
** FUNCTION PROTOTYPES **
|
||||
******************************************************************************/
|
||||
void *rrh_eNB_rx_thread(void *);
|
||||
void *rrh_eNB_tx_thread(void *);
|
||||
void *rrh_proc_eNB_thread(void *);
|
||||
void *rrh_eNB_thread(void *);
|
||||
void set_rt_period( openair0_config_t openair0_cfg);
|
||||
void print_dev_config(openair0_device device);
|
||||
|
||||
openair0_timestamp timestamp_eNB_tx[4]= {0,0,0,0},timestamp_eNB_rx[4]= {0,0,0,0};
|
||||
openair0_timestamp nrt_eNB_counter[4]= {0,0,0,0};
|
||||
|
||||
pthread_t main_rrh_eNB_thread;
|
||||
pthread_attr_t attr, attr_proc;
|
||||
struct sched_param sched_param_rrh;
|
||||
pthread_cond_t sync_eNB_cond[4];
|
||||
pthread_mutex_t sync_eNB_mutex[4];
|
||||
|
||||
int32_t overflow_rx_buffer_eNB[4]= {0,0,0,0};
|
||||
int32_t nsamps_eNB[4]= {0,0,0,0};
|
||||
int32_t eNB_tx_started=0,eNB_rx_started=0;
|
||||
int32_t counter_eNB_rx[4]= {0,0,0,0};
|
||||
int32_t counter_eNB_tx[4]= {0,0,0,0};
|
||||
uint8_t RT_flag_eNB,NRT_flag_eNB;
|
||||
int32_t **tx_buffer_eNB, **rx_buffer_eNB;
|
||||
|
||||
void *rrh_eNB_thread_status;
|
||||
void *rx_eNB[2]; //to be fixed
|
||||
void *tx_eNB[2]; //to be fixed
|
||||
int sync_eNB_rx[4]= {-1,-1,-1,-1};
|
||||
|
||||
unsigned int rx_pos=0, next_rx_pos=0;
|
||||
unsigned int tx_pos=0, prev_tx_pos=0;
|
||||
|
||||
|
||||
/*! \fn void create_eNB_trx_threads( rrh_module_t *dev_enb, uint8_t RT_flag,uint8_t NRT_flag)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void create_eNB_trx_threads( rrh_module_t *dev_enb, uint8_t RT_flag, uint8_t NRT_flag){
|
||||
|
||||
//int i;
|
||||
int error_code_eNB;//, error_code_proc_eNB;
|
||||
|
||||
RT_flag_eNB=RT_flag;
|
||||
NRT_flag_eNB=NRT_flag;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
pthread_attr_setschedparam(&attr,&sched_param_rrh);
|
||||
pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
|
||||
/*
|
||||
for (i=0; i<4; i++) {
|
||||
pthread_mutex_init(&sync_eNB_mutex[i],NULL);
|
||||
pthread_cond_init(&sync_eNB_cond[i],NULL);
|
||||
}*/
|
||||
|
||||
error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)dev_enb);
|
||||
if (error_code_eNB) {
|
||||
printf("Error while creating eNB thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*! \fn void *rrh_eNB_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_eNB_thread(void *arg)
|
||||
{
|
||||
rrh_module_t *dev=(rrh_module_t *)arg;
|
||||
pthread_t eNB_rx_thread, eNB_tx_thread;
|
||||
int error_code_eNB_rx, error_code_eNB_tx;
|
||||
int16_t i,j;
|
||||
void *tmp;
|
||||
unsigned int samples_per_frame=0;
|
||||
|
||||
|
||||
while (rrh_exit==0) {
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX, 1 );
|
||||
|
||||
/* handshake with client to exchange parameters */
|
||||
dev->eth_dev.trx_reply_func(&dev->eth_dev);//change port make it plus_id
|
||||
/* prints received configuration parameters */
|
||||
print_dev_config(dev->eth_dev);
|
||||
set_rt_period(dev->eth_dev.openair0_cfg);
|
||||
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
|
||||
/* allocate memory for TX/RX buffers
|
||||
each antenna port has a TX and a RX buffer
|
||||
each TX and RX buffer is of (samples_per_frame + HEADER_SIZE) samples(int32_t) */
|
||||
rx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.rx_num_channels*sizeof(int32_t*));
|
||||
tx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.tx_num_channels*sizeof(int32_t*));
|
||||
|
||||
LOG_D(RRH,"rx ch %d %p and tx ch %d %p\n",
|
||||
dev->eth_dev.openair0_cfg.rx_num_channels,
|
||||
rx_buffer_eNB,
|
||||
dev->eth_dev.openair0_cfg.tx_num_channels,
|
||||
tx_buffer_eNB);
|
||||
/* rx_buffer_eNB points to the beginning of data */
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.rx_num_channels; i++) {
|
||||
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
|
||||
memset(tmp,0,sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
|
||||
rx_buffer_eNB[i]=( tmp + (HEADER_SIZE*sizeof(int32_t)) );
|
||||
LOG_D(RRH," rx ch %d %p |%p header=%d size=%d sample=%d spf=%d\n",
|
||||
i,
|
||||
rx_buffer_eNB[i],tmp,HEADER_SIZE,(sizeof(int32_t)*(samples_per_frame + HEADER_SIZE)),sizeof(int32_t),samples_per_frame);
|
||||
}
|
||||
/* tx_buffer_eNB points to the beginning of data */
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++) {
|
||||
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
|
||||
memset(tmp,0,sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
|
||||
tx_buffer_eNB[i]=( tmp + (HEADER_SIZE*sizeof(int32_t)) );
|
||||
LOG_D(RRH," tx ch %d %p| %p \n", i,tx_buffer_eNB[i],tmp);
|
||||
}
|
||||
/* dummy initialization for TX/RX buffers */
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++) {
|
||||
for (j=0; j<samples_per_frame; j++) {
|
||||
rx_buffer_eNB[i][j]=32+i;
|
||||
tx_buffer_eNB[i][j]=13+i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef LOWLATENCY
|
||||
error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev);
|
||||
error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev);
|
||||
LOG_D(RRH,"[eNB][SCHED] deadline scheduling applied to TX/RX threads\n");
|
||||
#else
|
||||
pthread_attr_t attr_eNB_rx, attr_eNB_tx;
|
||||
struct sched_param sched_param_eNB_rx, sched_param_eNB_tx;
|
||||
pthread_attr_init(&attr_eNB_rx);
|
||||
pthread_attr_init(&attr_eNB_tx);
|
||||
sched_param_eNB_rx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_param_eNB_tx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
pthread_attr_setschedparam(&attr_eNB_rx,&sched_param_eNB_rx);
|
||||
pthread_attr_setschedparam(&attr_eNB_tx,&sched_param_eNB_tx);
|
||||
pthread_attr_setschedpolicy(&attr_eNB_rx,SCHED_FIFO);
|
||||
pthread_attr_setschedpolicy(&attr_eNB_tx,SCHED_FIFO);
|
||||
|
||||
error_code_eNB_rx = pthread_create(&eNB_rx_thread, &attr_eNB_rx, rrh_eNB_rx_thread, (void *)dev);
|
||||
error_code_eNB_tx = pthread_create(&eNB_tx_thread, &attr_eNB_tx, rrh_eNB_tx_thread, (void *)dev);
|
||||
LOG_D(RRH,"[eNB][SCHED] FIFO scheduling applied to TX/RX threads\n");
|
||||
#endif
|
||||
|
||||
if (error_code_eNB_rx) {
|
||||
LOG_E(RRH,"[eNB] Error while creating eNB RX thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (error_code_eNB_tx) {
|
||||
LOG_E(RRH,"[eNB] Error while creating eNB TX thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while (rrh_exit==0)
|
||||
sleep(1);
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,0 );
|
||||
} //while (eNB_exit==0)
|
||||
|
||||
rrh_eNB_thread_status = 0;
|
||||
pthread_exit(&rrh_eNB_thread_status);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! \fn void *rrh_eNB_rx_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_eNB_rx_thread(void *arg){
|
||||
|
||||
/* measuremnt related vars */
|
||||
struct timespec time0,time1,time2;
|
||||
unsigned long long max_rx_time=0, min_rx_time=rt_period, total_rx_time=0, average_rx_time=rt_period, s_period=0, trial=0;
|
||||
int trace_cnt=0;
|
||||
|
||||
struct timespec time_req_1us, time_rem_1us;
|
||||
rrh_module_t *dev = (rrh_module_t *)arg;
|
||||
ssize_t bytes_sent;
|
||||
int i, spp ,pck_rx=0;
|
||||
openair0_vtimestamp last_hw_counter=0; //volatile int64_t last_hw_counter=0;---> read
|
||||
unsigned int samples_per_frame=0;
|
||||
uint8_t loopback=0,measurements=0;
|
||||
|
||||
//RTIME sleep_ns=1000;
|
||||
time_req_1us.tv_sec = 0;
|
||||
time_req_1us.tv_nsec =1000; //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue
|
||||
spp = dev->eth_dev.openair0_cfg.samples_per_packet;
|
||||
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
loopback = dev->loopback;
|
||||
measurements = dev->measurements;
|
||||
next_rx_pos = spp;
|
||||
|
||||
LOG_I(RRH,"rt period is set to %d\n",rt_period);
|
||||
#ifdef LOWLATENCY
|
||||
struct sched_attr attr;
|
||||
unsigned int flags = 0;
|
||||
|
||||
attr.size = sizeof(attr);
|
||||
attr.sched_flags = 0;
|
||||
attr.sched_nice = 0;
|
||||
attr.sched_priority = 0;
|
||||
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = (0.1 * 100) * 10000; //
|
||||
attr.sched_deadline = rt_period;// 0.1 * 1000000; //
|
||||
attr.sched_period = rt_period; //0.1 * 1000000; // each TX/RX thread has
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
perror("[SCHED] eNB RX thread: sched_setattr failed (run with sudo)\n");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (rrh_exit == 0) {
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 1 );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT, hw_counter );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT, last_hw_counter );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK, pck_rx );
|
||||
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.rx_num_channels; i++){
|
||||
if (!eNB_rx_started) {
|
||||
eNB_rx_started=1; // set this flag to 1 to indicate that eNB started
|
||||
if (RT_flag_eNB==1) {
|
||||
last_hw_counter=hw_counter;
|
||||
}
|
||||
} else {
|
||||
if (RT_flag_eNB==1) {
|
||||
if (hw_counter > last_hw_counter+1) {
|
||||
printf("LR");
|
||||
} else {
|
||||
while (hw_counter < last_hw_counter+1){
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 1 );
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
//rt_sleep_ns(sleep_ns);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (measurements == 1 )
|
||||
clock_gettime(CLOCK_MONOTONIC,&time1);
|
||||
|
||||
/* LOG_I(RRH,"send for%d at %d with %d |%d|%d| \n",i,rx_pos,timestamp_eNB_rx[i],((timestamp_eNB_rx[i]+spp)%samples_per_frame),next_rx_pos );
|
||||
|
||||
if ((timestamp_UE_tx[i]%samples_per_frame < next_rx_pos) && (UE_tx_started==1)) {
|
||||
printf("eNB underflow\n");
|
||||
if (NRT_flag_eNB==1) {
|
||||
while ((timestamp_UE_tx[i]%samples_per_frame) < spp)
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
}
|
||||
}
|
||||
if (((rx_pos)< timestamp_UE_tx[i]%samples_per_frame) && (next_rx_pos > (timestamp_UE_tx[i]%samples_per_frame)) && (UE_tx_started==1)) {
|
||||
printf("eNB underflow\n");
|
||||
if (NRT_flag_eNB==1) {
|
||||
while (next_rx_pos > (timestamp_UE_tx[i]%samples_per_frame))
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (loopback == 1 ) {
|
||||
if (sync_eNB_rx[i]==0) {
|
||||
rx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];
|
||||
LOG_I(RRH,"tx_buffer_eNB[i][tx_pos]=%d ,tx_pos=%d\n",tx_buffer_eNB[i][tx_pos],tx_pos);
|
||||
}
|
||||
else{
|
||||
rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
|
||||
LOG_I(RRH,"rx_buffer_eNB[i][rx_pos]=%d ,rx_pos=%d\n",rx_buffer_eNB[i][rx_pos],rx_pos);
|
||||
}
|
||||
}
|
||||
|
||||
rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_TS, timestamp_eNB_rx[i]&0xffffffff );
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
|
||||
|
||||
//LOG_D(RRH,"rx_buffer_eNB[i][rx_pos]=%p ,rx_pos=%d, i=%d ts=%d\n",&rx_buffer_eNB[i][rx_pos],rx_pos,i,timestamp_eNB_rx[i]);
|
||||
if ((bytes_sent = dev->eth_dev.trx_write_func (&dev->eth_dev,
|
||||
timestamp_eNB_rx[i],
|
||||
rx_eNB,
|
||||
spp,
|
||||
i,
|
||||
0))<0){
|
||||
perror("RRH eNB : sendto for RX");
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
|
||||
|
||||
timestamp_eNB_rx[i]+=spp;
|
||||
last_hw_counter=hw_counter;
|
||||
|
||||
if (measurements == 1 ) {
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC,&time2);
|
||||
|
||||
if (trace_cnt++ > 10) {
|
||||
total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec);
|
||||
if (total_rx_time < 0)
|
||||
total_rx_time=1000000000-total_rx_time;
|
||||
|
||||
if ((total_rx_time > 0) && (total_rx_time < 1000000000)) {
|
||||
trial++;
|
||||
if (total_rx_time < min_rx_time)
|
||||
min_rx_time = total_rx_time;
|
||||
if (total_rx_time > max_rx_time){
|
||||
max_rx_time = total_rx_time;
|
||||
LOG_D(RRH,"Max value %d update at rx_position %d \n",timestamp_eNB_rx[i], rx_pos);
|
||||
}
|
||||
average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1);
|
||||
}
|
||||
if (s_period++ == PRINTF_PERIOD) {
|
||||
s_period=0;
|
||||
LOG_I(RRH,"Average eNB RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&time0,&time2,sizeof(struct timespec));
|
||||
}
|
||||
|
||||
if (loopback == 1 ){
|
||||
pthread_mutex_lock(&sync_eNB_mutex[i]);
|
||||
sync_eNB_rx[i]--;
|
||||
pthread_mutex_unlock(&sync_eNB_mutex[i]);
|
||||
}
|
||||
|
||||
}//for each antenna
|
||||
|
||||
rx_pos += spp;
|
||||
pck_rx++;
|
||||
next_rx_pos=(rx_pos+spp);
|
||||
|
||||
if (next_rx_pos >= samples_per_frame)
|
||||
next_rx_pos -= samples_per_frame;
|
||||
if (rx_pos >= samples_per_frame)
|
||||
rx_pos -= samples_per_frame;
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 0 );
|
||||
} //while (eNB_exit==0)
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void *rrh_eNB_tx_thread(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *rrh_eNB_tx_thread(void *arg){
|
||||
|
||||
struct timespec time0a,time0,time1,time2;
|
||||
|
||||
rrh_module_t *dev = (rrh_module_t *)arg;
|
||||
struct timespec time_req_1us, time_rem_1us;
|
||||
ssize_t bytes_received;
|
||||
int spp,i;
|
||||
openair0_timestamp last_hw_counter=0;
|
||||
unsigned int samples_per_frame=0;
|
||||
uint8_t loopback=0,measurements=0;
|
||||
|
||||
#ifdef LOWLATENCY
|
||||
struct sched_attr attr;
|
||||
unsigned int flags = 0;
|
||||
|
||||
attr.size = sizeof(attr);
|
||||
attr.sched_flags = 0;
|
||||
attr.sched_nice = 0;
|
||||
attr.sched_priority = 0;
|
||||
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = (0.1 * 100) * 10000; //
|
||||
attr.sched_deadline = rt_period;//0.1 * 1000000; //
|
||||
attr.sched_period = rt_period;//0.1 * 1000000; // each TX/RX thread has
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
perror("[SCHED] eNB TX thread: sched_setattr failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
tx_pos=0;
|
||||
time_req_1us.tv_sec = 0;
|
||||
time_req_1us.tv_nsec = 1000;
|
||||
spp = dev->eth_dev.openair0_cfg.samples_per_packet;
|
||||
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
||||
loopback = dev->loopback;
|
||||
measurements = dev->measurements;
|
||||
|
||||
while (rrh_exit == 0) {
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 1 );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT, hw_counter );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT, last_hw_counter );
|
||||
|
||||
if (measurements == 1 )
|
||||
clock_gettime(CLOCK_MONOTONIC,&time0a);
|
||||
|
||||
for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++){
|
||||
if (!eNB_tx_started) {
|
||||
eNB_tx_started=1; // set this flag to 1 to indicate that eNB started
|
||||
if (RT_flag_eNB==1) {
|
||||
last_hw_counter=hw_counter;
|
||||
}
|
||||
} else {
|
||||
if (RT_flag_eNB==1) {
|
||||
if (hw_counter > last_hw_counter+1) {
|
||||
printf("LT");
|
||||
} else {
|
||||
while (hw_counter < last_hw_counter+1){
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 1 );
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (measurements == 1 )
|
||||
clock_gettime(CLOCK_MONOTONIC,&time1);
|
||||
|
||||
tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos );
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
|
||||
bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev,
|
||||
×tamp_eNB_tx[i],
|
||||
tx_eNB,
|
||||
spp,
|
||||
i);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_eNB_tx[i]&0xffffffff );
|
||||
if (NRT_flag_eNB==1) {
|
||||
nrt_eNB_counter[i]++;
|
||||
}
|
||||
prev_tx_pos=tx_pos;
|
||||
tx_pos += spp;
|
||||
|
||||
if (tx_pos >= samples_per_frame)
|
||||
tx_pos -= samples_per_frame;
|
||||
|
||||
last_hw_counter=hw_counter;
|
||||
|
||||
if (loopback ==1 ) {
|
||||
while (sync_eNB_rx[i]==0)
|
||||
nanosleep(&time_req_1us,&time_rem_1us);
|
||||
|
||||
pthread_mutex_lock(&sync_eNB_mutex[i]);
|
||||
sync_eNB_rx[i]++;
|
||||
pthread_mutex_unlock(&sync_eNB_mutex[i]);
|
||||
}
|
||||
|
||||
}
|
||||
if (measurements == 1 ) {
|
||||
clock_gettime(CLOCK_MONOTONIC,&time2);
|
||||
memcpy(&time0,&time2,sizeof(struct timespec));
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 0 );
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
//needs to be fixed
|
||||
void set_rt_period( openair0_config_t openair0_cfg){
|
||||
|
||||
AssertFatal(openair0_cfg.samples_per_frame > 0, "invalide samples per frame !%u\n",openair0_cfg.samples_per_frame);
|
||||
AssertFatal(openair0_cfg.samples_per_packet > 0, "invalide samples per packets !%u\n",openair0_cfg.samples_per_packet);
|
||||
rt_period= (double)(openair0_cfg.samples_per_packet/(openair0_cfg.samples_per_frame/10.0)*1000000);
|
||||
AssertFatal(rt_period > 0, "invalide rt period !%u\n", rt_period);
|
||||
LOG_I(RRH,"Real time period is set to %d ns.\n",rt_period);
|
||||
// set the calibration parameters for ETH later: check with RK
|
||||
openair0_cfg.tx_delay=0;
|
||||
openair0_cfg.tx_forward_nsamps=0;
|
||||
|
||||
//only in case of NRT with emulated UE
|
||||
create_timer_thread();
|
||||
// usleep(rt_period*1000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void print_dev_config(openair0_device device){
|
||||
|
||||
printf("\tMod_id=%d\n \tlog level=%d\n \tDL_RB=%d\n \tspf=%d\n \tsr=%f\n \tspp=%d\n \ttx_delay=%d\n \ttx_forwd_samps=%d\n \trx_ch=%d\n \ttx_ch=%d\n \trx_freq=%f\n \ttx_freq=%f\n \trxg_mode=%d\n \trx_gain=%f\n \ttx_gain=%f\n \trx_bw=%f\n \ttx_bw=%f\n \tautocal=%d\n \trem_addr %s:%d\n \tmy_addr %s:%d\n",
|
||||
device.openair0_cfg.Mod_id,
|
||||
device.openair0_cfg.log_level,
|
||||
device.openair0_cfg.num_rb_dl,
|
||||
device.openair0_cfg.samples_per_frame,
|
||||
device.openair0_cfg.sample_rate,
|
||||
device.openair0_cfg.samples_per_packet,
|
||||
device.openair0_cfg.tx_delay,
|
||||
device.openair0_cfg.tx_forward_nsamps,
|
||||
device.openair0_cfg.rx_num_channels,
|
||||
device.openair0_cfg.tx_num_channels,
|
||||
device.openair0_cfg.rx_freq[0],
|
||||
device.openair0_cfg.tx_freq[0],
|
||||
device.openair0_cfg.rxg_mode[0],
|
||||
device.openair0_cfg.rx_gain[0],
|
||||
device.openair0_cfg.tx_gain[0],
|
||||
device.openair0_cfg.rx_bw,
|
||||
device.openair0_cfg.tx_bw,
|
||||
device.openair0_cfg.autocal[0],
|
||||
device.openair0_cfg.remote_ip,
|
||||
device.openair0_cfg.remote_port,
|
||||
device.openair0_cfg.my_ip,
|
||||
device.openair0_cfg.my_port
|
||||
);
|
||||
|
||||
}
|
||||
+142
-130
@@ -45,15 +45,11 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <linux/sched.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <getopt.h>
|
||||
#include <syscall.h>
|
||||
#include <pthread.h> // for gettid
|
||||
|
||||
#include "rt_wrapper.h"
|
||||
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
|
||||
@@ -156,6 +152,10 @@ int32_t **txdata;
|
||||
int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
|
||||
int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
|
||||
|
||||
uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
|
||||
uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
|
||||
double cpuf;
|
||||
|
||||
void fill_ue_band_info(void);
|
||||
#ifdef XFORMS
|
||||
// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
|
||||
@@ -293,9 +293,9 @@ static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/;
|
||||
char ref[128] = "internal";
|
||||
char channels[128] = "0";
|
||||
|
||||
unsigned int samples_per_frame = 307200;
|
||||
unsigned int tx_forward_nsamps=0;
|
||||
int tx_delay;
|
||||
//unsigned int samples_per_frame = 307200;
|
||||
//unsigned int tx_forward_nsamps=0;
|
||||
//int tx_delay;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -380,20 +380,6 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe)
|
||||
return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
|
||||
}
|
||||
|
||||
#ifdef LOWLATENCY
|
||||
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
|
||||
{
|
||||
|
||||
return syscall(__NR_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
|
||||
|
||||
int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned int flags)
|
||||
{
|
||||
|
||||
return syscall(__NR_sched_getattr, pid, attr, size, flags);
|
||||
}
|
||||
#endif
|
||||
#if !defined(ENABLE_ITTI)
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
@@ -474,40 +460,6 @@ void exit_fun(const char* s)
|
||||
//exit (-1);
|
||||
}
|
||||
|
||||
static int latency_target_fd = -1;
|
||||
static int32_t latency_target_value = 0;
|
||||
/* Latency trick - taken from cyclictest.c
|
||||
* if the file /dev/cpu_dma_latency exists,
|
||||
* open it and write a zero into it. This will tell
|
||||
* the power management system not to transition to
|
||||
* a high cstate (in fact, the system acts like idle=poll)
|
||||
* When the fd to /dev/cpu_dma_latency is closed, the behavior
|
||||
* goes back to the system default.
|
||||
*
|
||||
* Documentation/power/pm_qos_interface.txt
|
||||
*/
|
||||
static void set_latency_target(void)
|
||||
{
|
||||
struct stat s;
|
||||
int ret;
|
||||
|
||||
if (stat("/dev/cpu_dma_latency", &s) == 0) {
|
||||
latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR);
|
||||
|
||||
if (latency_target_fd == -1)
|
||||
return;
|
||||
|
||||
ret = write(latency_target_fd, &latency_target_value, 4);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno));
|
||||
close(latency_target_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XFORMS
|
||||
|
||||
@@ -1082,7 +1034,8 @@ static void* eNB_thread_tx( void* param )
|
||||
|
||||
// This creates a 1ms reservation every 10ms period
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 0.9 * 1000000; // each tx thread requires 1ms to finish its job
|
||||
//attr.sched_runtime = 0.9 * 1000000; // each tx thread requires 1ms to finish its job
|
||||
attr.sched_runtime = (uint64_t) (get_runtime_tx(proc->subframe, runtime_phy_tx, target_dl_mcs,frame_parms[0]->N_RB_DL,cpuf,PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx) * 1000000); // each tx thread requires 1ms to finish its job
|
||||
attr.sched_deadline = 1 * 1000000; // each tx thread will finish within 1ms
|
||||
attr.sched_period = 1 * 10000000; // each tx thread has a period of 10ms from the starting point
|
||||
|
||||
@@ -1196,13 +1149,20 @@ static void* eNB_thread_tx( void* param )
|
||||
|
||||
if (proc->frame_tx==1024)
|
||||
proc->frame_tx=0;
|
||||
|
||||
stop_meas( &softmodem_stats_tx_sf[proc->subframe] );
|
||||
#ifdef LOWLATENCY
|
||||
if (opp_enabled){
|
||||
if(softmodem_stats_tx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB, (softmodem_stats_tx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
print_meas_now(&softmodem_stats_tx_sf[proc->subframe],"eNB_TX_SF",proc->subframe, tx_time_file);
|
||||
|
||||
}
|
||||
|
||||
stop_meas( &softmodem_stats_tx_sf[proc->subframe] );
|
||||
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 0 );
|
||||
|
||||
#ifdef HARD_RT
|
||||
@@ -1276,7 +1236,7 @@ static void* eNB_thread_rx( void* param )
|
||||
|
||||
/* This creates a 2ms reservation every 10ms period*/
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 1 * 1000000; // each rx thread must finish its job in the worst case in 2ms
|
||||
attr.sched_runtime = (uint64_t)(get_runtime_rx(proc->subframe, runtime_phy_rx, target_ul_mcs,frame_parms[0]->N_RB_DL,cpuf,PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx) * 1000000); // each tx thread requires 1ms to finish its job
|
||||
attr.sched_deadline = 1 * 1000000; // each rx thread will finish within 2ms
|
||||
attr.sched_period = 1 * 10000000; // each rx thread has a period of 10ms from the starting point
|
||||
|
||||
@@ -1355,11 +1315,17 @@ static void* eNB_thread_rx( void* param )
|
||||
proc->frame_rx=0;
|
||||
|
||||
stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
|
||||
#ifdef LOWLATENCY
|
||||
if (opp_enabled){
|
||||
if(softmodem_stats_rx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RX_ENB, (softmodem_stats_rx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
print_meas_now(&softmodem_stats_rx_sf[proc->subframe],"eNB_RX_SF",proc->subframe, rx_time_file);
|
||||
|
||||
}
|
||||
|
||||
stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
|
||||
//stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 0 );
|
||||
|
||||
#ifdef HARD_RT
|
||||
@@ -1409,7 +1375,6 @@ void init_eNB_proc(void)
|
||||
pthread_attr_setschedpolicy (&attr_eNB_proc_rx[CC_id][i], SCHED_FIFO);
|
||||
printf("Setting OS scheduler to SCHED_FIFO for eNB [cc%d][thread%d] \n",CC_id, i);
|
||||
#endif
|
||||
|
||||
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_tx = -1;
|
||||
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_rx = -1;
|
||||
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe = i;
|
||||
@@ -1418,8 +1383,13 @@ void init_eNB_proc(void)
|
||||
pthread_mutex_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_rx, NULL);
|
||||
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx, NULL);
|
||||
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx, NULL);
|
||||
#ifndef LOWLATENCY
|
||||
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, &attr_eNB_proc_tx[CC_id][i], eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
|
||||
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, &attr_eNB_proc_rx[CC_id][i], eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
|
||||
#else
|
||||
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, NULL, eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
|
||||
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, NULL, eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
|
||||
#endif
|
||||
char name[16];
|
||||
snprintf( name, sizeof(name), "TX %d", i );
|
||||
pthread_setname_np( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, name );
|
||||
@@ -1574,7 +1544,7 @@ static void* eNB_thread( void* arg )
|
||||
int hw_subframe = 0; // 0..NUM_ENB_THREADS-1 => 0..9
|
||||
spp = openair0_cfg[0].samples_per_packet;
|
||||
unsigned int rx_pos = 0;
|
||||
unsigned int tx_pos = spp*tx_delay;
|
||||
unsigned int tx_pos = 0; //spp*tx_delay;
|
||||
#endif
|
||||
int CC_id=0;
|
||||
struct timespec trx_time0, trx_time1, trx_time2;
|
||||
@@ -1591,11 +1561,11 @@ static void* eNB_thread( void* arg )
|
||||
attr.sched_nice = 0;
|
||||
attr.sched_priority = 0;
|
||||
|
||||
/* This creates a .5 ms reservation */
|
||||
/* This creates a .2 ms reservation */
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 0.2 * 1000000;
|
||||
attr.sched_deadline = 0.9 * 1000000;
|
||||
attr.sched_period = 1.0 * 1000000;
|
||||
attr.sched_runtime = (0.2 * 100) * 10000;
|
||||
attr.sched_deadline = (0.9 * 100) * 10000;
|
||||
attr.sched_period = 1 * 1000000;
|
||||
|
||||
|
||||
/* pin the eNB main thread to CPU0*/
|
||||
@@ -1674,7 +1644,7 @@ static void* eNB_thread( void* arg )
|
||||
first_run=0;
|
||||
|
||||
if (diff<0)
|
||||
diff = diff +150;
|
||||
diff = diff + 150;
|
||||
|
||||
LOG_I(HW,"eNB Frame %d, time %llu: slot %d, hw_slot %d, diff %d\n",frame, rt_get_time_ns(), slot, hw_slot, diff);
|
||||
}
|
||||
@@ -1774,18 +1744,21 @@ static void* eNB_thread( void* arg )
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &trx_time0 );
|
||||
|
||||
// prepare rx buffer pointers
|
||||
for (int i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx; i++)
|
||||
rxp[i] = (void*)&rxdata[i][rx_pos];
|
||||
|
||||
start_meas( &softmodem_stats_hw );
|
||||
start_meas( &softmodem_stats_hw );
|
||||
|
||||
openair0_timestamp timestamp;
|
||||
rxs = openair0.trx_read_func(&openair0,
|
||||
×tamp,
|
||||
rxp,
|
||||
spp,
|
||||
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx);
|
||||
int i=0;
|
||||
// prepare rx buffer pointers
|
||||
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx; i++){
|
||||
rxp[i] = (void*)&rxdata[i][rx_pos];
|
||||
// check if nsymb_read == spp
|
||||
// map antenna port i to the cc_id. Now use the 1:1 mapping
|
||||
rxs = openair0.trx_read_func(&openair0,
|
||||
×tamp,
|
||||
rxp,
|
||||
spp,
|
||||
i);
|
||||
}
|
||||
stop_meas( &softmodem_stats_hw );
|
||||
clock_gettime( CLOCK_MONOTONIC, &trx_time1 );
|
||||
|
||||
@@ -1796,23 +1769,26 @@ static void* eNB_thread( void* arg )
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
|
||||
|
||||
// Transmit TX buffer based on timestamp from RX
|
||||
|
||||
|
||||
if (frame > 50) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
|
||||
|
||||
// prepare tx buffer pointers
|
||||
for (int i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx; i++)
|
||||
txp[i] = (void*)&txdata[i][tx_pos];
|
||||
|
||||
if (frame > 50) {
|
||||
openair0.trx_write_func(&openair0,
|
||||
(timestamp+(tx_delay*spp)-tx_forward_nsamps),
|
||||
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx; i++){
|
||||
txp[i] = (void*)&rxdata[i][tx_pos];
|
||||
//printf("tx_pos %d ts %d, ts_offset %d txp[i] %p, ap %d\n", tx_pos, timestamp, (timestamp+(tx_delay*spp)-tx_forward_nsamps),txp[i], i);
|
||||
// if symb_written < spp ==> error
|
||||
openair0.trx_write_func(&openair0,
|
||||
(timestamp+(openair0_cfg[card].tx_delay*spp)-openair0_cfg[card].tx_forward_nsamps),
|
||||
txp,
|
||||
spp,
|
||||
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx,
|
||||
i,
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, timestamp&0xffffffff );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+(tx_delay*spp)-tx_forward_nsamps)&0xffffffff );
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+(openair0_cfg[card].tx_delay*spp)-openair0_cfg[card].tx_forward_nsamps)&0xffffffff );
|
||||
|
||||
stop_meas( &softmodem_stats_mt );
|
||||
clock_gettime( CLOCK_MONOTONIC, &trx_time2 );
|
||||
@@ -1856,12 +1832,12 @@ static void* eNB_thread( void* arg )
|
||||
rx_pos += spp;
|
||||
tx_pos += spp;
|
||||
|
||||
if (tx_pos >= samples_per_frame)
|
||||
tx_pos -= samples_per_frame;
|
||||
if (tx_pos >= openair0_cfg[card].samples_per_frame)
|
||||
tx_pos -= openair0_cfg[card].samples_per_frame;
|
||||
}
|
||||
|
||||
if (rx_pos >= samples_per_frame)
|
||||
rx_pos -= samples_per_frame;
|
||||
if (rx_pos >= openair0_cfg[card].samples_per_frame)
|
||||
rx_pos -= openair0_cfg[card].samples_per_frame;
|
||||
|
||||
|
||||
#endif // USRP
|
||||
@@ -2573,8 +2549,10 @@ int main( int argc, char **argv )
|
||||
VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd");
|
||||
}
|
||||
|
||||
if (opp_enabled ==1)
|
||||
if (opp_enabled ==1){
|
||||
reset_opp_meas();
|
||||
}
|
||||
cpuf=get_cpu_freq_GHz();
|
||||
|
||||
#if defined(ENABLE_ITTI)
|
||||
|
||||
@@ -2585,10 +2563,11 @@ int main( int argc, char **argv )
|
||||
}
|
||||
|
||||
itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file);
|
||||
#endif
|
||||
|
||||
// initialize mscgen log after ITTI
|
||||
MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OPENAIR2
|
||||
|
||||
if (opt_type != OPT_NONE) {
|
||||
@@ -2834,7 +2813,10 @@ int main( int argc, char **argv )
|
||||
openair_daq_vars.target_ue_ul_mcs=target_ul_mcs;
|
||||
|
||||
}
|
||||
|
||||
#ifndef RTAI
|
||||
fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx);
|
||||
cpuf=get_cpu_freq_GHz();
|
||||
#endif
|
||||
|
||||
dump_frame_parms(frame_parms[0]);
|
||||
|
||||
@@ -2842,56 +2824,64 @@ int main( int argc, char **argv )
|
||||
sample_rate = 30.72e6;
|
||||
bw = 10.0e6;
|
||||
#ifndef EXMIMO
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
samples_per_frame = 307200;
|
||||
openair0_cfg[card].sample_rate=30.72e6;
|
||||
openair0_cfg[card].samples_per_packet = 2048;
|
||||
openair0_cfg[card].samples_per_frame = 307200;
|
||||
openair0_cfg[card].tx_bw = 10e6;
|
||||
openair0_cfg[card].rx_bw = 10e6;
|
||||
// from usrp_time_offset
|
||||
tx_forward_nsamps = 175;
|
||||
tx_delay = 8;
|
||||
openair0_cfg[card].tx_forward_nsamps = 175;
|
||||
openair0_cfg[card].tx_delay = 8;
|
||||
#endif
|
||||
} else if(frame_parms[0]->N_RB_DL == 50) {
|
||||
sample_rate = 15.36e6;
|
||||
bw = 5.0e6;
|
||||
#ifndef EXMIMO
|
||||
openair0_cfg[0].samples_per_packet = 2048;
|
||||
samples_per_frame = 153600;
|
||||
openair0_cfg[card].sample_rate=15.36e6;
|
||||
openair0_cfg[card].samples_per_packet = 2048;
|
||||
openair0_cfg[card].samples_per_frame = 153600;
|
||||
openair0_cfg[card].tx_bw = 5e6;
|
||||
openair0_cfg[card].rx_bw = 5e6;
|
||||
tx_forward_nsamps = 95;
|
||||
tx_delay = 5;
|
||||
openair0_cfg[card].tx_forward_nsamps = 95;
|
||||
openair0_cfg[card].tx_delay = 5;
|
||||
#endif
|
||||
} else if (frame_parms[0]->N_RB_DL == 25) {
|
||||
sample_rate = 7.68e6;
|
||||
bw = 2.5e6;
|
||||
#ifndef EXMIMO
|
||||
samples_per_frame = 76800;
|
||||
openair0_cfg[card].sample_rate=7.68e6;
|
||||
openair0_cfg[card].samples_per_frame = 76800;
|
||||
openair0_cfg[card].tx_bw = 2.5e6;
|
||||
openair0_cfg[card].rx_bw = 2.5e6;
|
||||
openair0_cfg[0].samples_per_packet = 1024;
|
||||
openair0_cfg[card].samples_per_packet = 1024;
|
||||
#ifdef OAI_USRP
|
||||
tx_forward_nsamps = 70;
|
||||
tx_delay = 6;
|
||||
openair0_cfg[card].tx_forward_nsamps = 70;
|
||||
openair0_cfg[card].tx_delay = 6;
|
||||
#elif OAI_BLADERF
|
||||
tx_forward_nsamps = 70;
|
||||
tx_delay = 6;
|
||||
openair0_cfg[card].tx_forward_nsamps = 70;
|
||||
openair0_cfg[card].tx_delay = 6;
|
||||
#endif
|
||||
#endif
|
||||
} else if (frame_parms[0]->N_RB_DL == 6) {
|
||||
sample_rate = 1.92e6;
|
||||
bw = 0.96e6;
|
||||
#ifndef EXMIMO
|
||||
openair0_cfg[0].samples_per_packet = 256;
|
||||
samples_per_frame = 19200;
|
||||
openair0_cfg[card].sample_rate=1.92e6;
|
||||
openair0_cfg[card].samples_per_packet = 256;
|
||||
openair0_cfg[card].samples_per_frame = 19200;
|
||||
openair0_cfg[card].tx_bw = 1.5e6;
|
||||
openair0_cfg[card].rx_bw = 1.5e6;
|
||||
tx_forward_nsamps = 40;
|
||||
tx_delay = 8;
|
||||
openair0_cfg[card].tx_forward_nsamps = 40;
|
||||
openair0_cfg[card].tx_delay = 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ETHERNET
|
||||
|
||||
//calib needed
|
||||
openair0_cfg[card].tx_delay = 0;
|
||||
openair0_cfg[card].tx_forward_nsamps = 0;
|
||||
|
||||
if (frame_parms[0]->N_RB_DL == 6) openair0_cfg[0].samples_per_packet = 256;
|
||||
else openair0_cfg[0].samples_per_packet = 1024;
|
||||
|
||||
@@ -2911,14 +2901,14 @@ int main( int argc, char **argv )
|
||||
|
||||
if (UE_flag) {
|
||||
printf("ETHERNET: Configuring UE ETH for %s:%d\n",rrh_UE_ip,rrh_UE_port);
|
||||
openair0_cfg[card].rrh_ip = &rrh_UE_ip[0];
|
||||
openair0_cfg[card].rrh_port = rrh_UE_port;
|
||||
openair0_cfg[card].remote_ip = &rrh_UE_ip[0];
|
||||
openair0_cfg[card].remote_port = rrh_UE_port;
|
||||
} else {
|
||||
printf("ETHERNET: Configuring eNB ETH for %s:%d\n",rrh_eNB_ip,rrh_eNB_port);
|
||||
openair0_cfg[card].rrh_ip = &rrh_eNB_ip[0];
|
||||
openair0_cfg[card].rrh_port = rrh_eNB_port;
|
||||
openair0_cfg[card].remote_ip = &rrh_eNB_ip[0];
|
||||
openair0_cfg[card].remote_port = rrh_eNB_port;
|
||||
}
|
||||
|
||||
openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
|
||||
#endif
|
||||
openair0_cfg[card].sample_rate = sample_rate;
|
||||
openair0_cfg[card].tx_bw = bw;
|
||||
@@ -2967,7 +2957,22 @@ int main( int argc, char **argv )
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("Initializing openair0 ...");
|
||||
|
||||
#ifdef ETHERNET
|
||||
openair0.type=ETH_IF; // not used for the moment
|
||||
openair0_dev_init_eth(&openair0, &openair0_cfg[0]);
|
||||
#else
|
||||
#ifdef EXMIMO
|
||||
openair0.type=EXMIMO_IF;
|
||||
printf("Setting the HW to EXMIMO and initializing openair0 ...\n");
|
||||
#elif OAI_USRP
|
||||
openair0.type=USRP_IF;
|
||||
printf("Setting the HW to USRP and initializing openair0 ...\n");
|
||||
#elif OAI_BLADERF
|
||||
openair0.type=BLADERF_IF;
|
||||
printf("Setting the HW to BLADERF and initializing openair0 ...\n");
|
||||
#endif
|
||||
openair0.func_type = BBU_FUNC;
|
||||
openair0_cfg[0].log_level = glog_level;
|
||||
|
||||
|
||||
@@ -2979,6 +2984,7 @@ int main( int argc, char **argv )
|
||||
else if (mode==loop_through_memory) {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("Done\n");
|
||||
|
||||
@@ -3296,8 +3302,12 @@ int main( int argc, char **argv )
|
||||
|
||||
#ifndef EXMIMO
|
||||
#ifndef USRP_DEBUG
|
||||
<<<<<<< .mine
|
||||
openair0.trx_request_func(&openair0);
|
||||
=======
|
||||
if (mode!=loop_through_memory)
|
||||
openair0.trx_start_func(&openair0);
|
||||
>>>>>>> .r7708
|
||||
// printf("returning from usrp start streaming: %llu\n",get_usrp_time(&openair0));
|
||||
#endif
|
||||
#endif
|
||||
@@ -3543,17 +3553,18 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
|
||||
|
||||
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
|
||||
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
|
||||
rxdata[i] = (int32_t*)(16 + malloc16(16+samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
|
||||
rxdata[i] = (int32_t*)(16 + malloc16(16+openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
|
||||
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = rxdata[i]-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory
|
||||
memset(rxdata[i], 0, samples_per_frame*sizeof(int32_t));
|
||||
memset(rxdata[i], 0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
|
||||
printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i],rxdata[i],N_TA_offset);
|
||||
|
||||
}
|
||||
|
||||
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
|
||||
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
|
||||
txdata[i] = (int32_t*)(16 + malloc16(16 + samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
|
||||
txdata[i] = (int32_t*)(16 + malloc16(16 + openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
|
||||
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = txdata[i];
|
||||
memset(txdata[i], 0, samples_per_frame*sizeof(int32_t));
|
||||
memset(txdata[i],0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
|
||||
printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
|
||||
|
||||
}
|
||||
@@ -3564,26 +3575,27 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
|
||||
return(0);
|
||||
}
|
||||
|
||||
void reset_opp_meas(void)
|
||||
{
|
||||
void reset_opp_meas(void) {
|
||||
int sfn;
|
||||
reset_meas(&softmodem_stats_mt);
|
||||
reset_meas(&softmodem_stats_hw);
|
||||
|
||||
|
||||
for (sfn=0; sfn < 10; sfn++) {
|
||||
reset_meas(&softmodem_stats_tx_sf[sfn]);
|
||||
reset_meas(&softmodem_stats_rx_sf[sfn]);
|
||||
}
|
||||
}
|
||||
|
||||
void print_opp_meas(void)
|
||||
{
|
||||
void print_opp_meas(void) {
|
||||
|
||||
int sfn=0;
|
||||
print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL);
|
||||
print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);
|
||||
|
||||
|
||||
for (sfn=0; sfn < 10; sfn++) {
|
||||
print_meas(&softmodem_stats_tx_sf[sfn],"[eNB][total_phy_proc_tx]",NULL, NULL);
|
||||
print_meas(&softmodem_stats_rx_sf[sfn],"[eNB][total_phy_proc_rx]",NULL,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+16
-16
@@ -119,8 +119,8 @@ extern int oai_exit;
|
||||
extern int32_t **rxdata;
|
||||
extern int32_t **txdata;
|
||||
|
||||
extern unsigned int tx_forward_nsamps;
|
||||
extern int tx_delay;
|
||||
//extern unsigned int tx_forward_nsamps;
|
||||
//extern int tx_delay;
|
||||
|
||||
extern int rx_input_level_dBm;
|
||||
extern uint8_t exit_missed_slots;
|
||||
@@ -583,9 +583,9 @@ static void *UE_thread_tx(void *arg)
|
||||
|
||||
/* This creates a 1ms reservation every 10ms period*/
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 1 * 900000; // each tx thread requires .5ms to finish its job
|
||||
attr.sched_deadline =1 * 1000000; // each tx thread will finish within 1ms
|
||||
attr.sched_period = 1 * 1000000; // each tx thread has a period of 1ms from the starting point
|
||||
attr.sched_runtime = (0.9 * 100) * 10000; // each tx thread requires .5ms to finish its job
|
||||
attr.sched_deadline = (1 * 100) * 10000; // each tx thread will finish within 1ms
|
||||
attr.sched_period = (1 * 100) * 10000; // each tx thread has a period of 1ms from the starting point
|
||||
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
@@ -732,9 +732,9 @@ static void *UE_thread_rx(void *arg)
|
||||
|
||||
// This creates a .5ms reservation every 1ms period
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 1 * 900000; // each rx thread requires 1ms to finish its job
|
||||
attr.sched_deadline =1 * 1000000; // each rx thread will finish within 1ms
|
||||
attr.sched_period = 1 * 1000000; // each rx thread has a period of 1ms from the starting point
|
||||
attr.sched_runtime = (0.9 * 100) * 10000;//900000; // each rx thread requires 1ms to finish its job
|
||||
attr.sched_deadline = (1 * 100) * 10000; // each rx thread will finish within 1ms
|
||||
attr.sched_period = (1 * 100) * 10000; // each rx thread has a period of 1ms from the starting point
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
perror("[SCHED] UE_thread_rx : sched_setattr failed\n");
|
||||
@@ -938,7 +938,7 @@ void *UE_thread(void *arg)
|
||||
static int UE_thread_retval;
|
||||
PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
|
||||
int spp = openair0_cfg[0].samples_per_packet;
|
||||
int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=spp*tx_delay;
|
||||
int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=spp*openair0_cfg[0].tx_delay;
|
||||
int dummy[2][spp];
|
||||
int dummy_dump = 0;
|
||||
int tx_enabled = 0;
|
||||
@@ -972,9 +972,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
// This creates a .5 ms reservation
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 0.25 * 1000000;
|
||||
attr.sched_deadline = 0.25 * 1000000;
|
||||
attr.sched_period = 0.5 * 1000000;
|
||||
attr.sched_runtime = (0.25 * 100) * 10000;
|
||||
attr.sched_deadline = (0.25 * 100) * 10000;
|
||||
attr.sched_period = (0.5 * 100) * 10000;
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
perror("[SCHED] main eNB thread: sched_setattr failed\n");
|
||||
@@ -1056,7 +1056,7 @@ void *UE_thread(void *arg)
|
||||
txp[i] = (void*)&txdata[i][txpos];
|
||||
|
||||
openair0.trx_write_func(&openair0,
|
||||
(timestamp+spp*tx_delay-tx_forward_nsamps),
|
||||
(timestamp+spp*openair0_cfg[0].tx_delay-openair0_cfg[0].tx_forward_nsamps),
|
||||
txp,
|
||||
spp - ((first_rx==1) ? rx_off_diff : 0),
|
||||
UE->lte_frame_parms.nb_antennas_tx,
|
||||
@@ -1353,9 +1353,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
// This creates a .25 ms reservation
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = 0.1 * 1000000;
|
||||
attr.sched_deadline = 0.25 * 1000000;
|
||||
attr.sched_period = 0.5 * 1000000;
|
||||
attr.sched_runtime = (0.1 * 100) * 10000;
|
||||
attr.sched_deadline = (0.25 * 100) * 10000;
|
||||
attr.sched_period = (0.5 * 100) * 10000;
|
||||
|
||||
// pin the UE main thread to CPU0
|
||||
// if (pthread_setaffinity_np(pthread_self(), sizeof(mask),&mask) <0) {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
[*]
|
||||
[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
|
||||
[*] Thu Jul 9 09:53:25 2015
|
||||
[*]
|
||||
[dumpfile] "/tmp/openair_dump_eNB.vcd"
|
||||
[dumpfile_mtime] "Thu Jul 9 09:52:29 2015"
|
||||
[dumpfile_size] 170586112
|
||||
[savefile] "/home/sud/openair4G/targets/RT/USER/eNB2.gtkw"
|
||||
[timestart] 16177999000
|
||||
[size] 1535 876
|
||||
[pos] -1 -1
|
||||
*-17.749426 16178576148 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||
[sst_width] 224
|
||||
[signals_width] 230
|
||||
[sst_expanded] 1
|
||||
[sst_vpaned_height] 230
|
||||
@28
|
||||
[color] 1
|
||||
functions.eNB_rx
|
||||
functions.eNB_rx_sleep
|
||||
[color] 7
|
||||
functions.trx_write
|
||||
@c00024
|
||||
variables.rxcnt[63:0]
|
||||
@28
|
||||
(0)variables.rxcnt[63:0]
|
||||
(1)variables.rxcnt[63:0]
|
||||
(2)variables.rxcnt[63:0]
|
||||
(3)variables.rxcnt[63:0]
|
||||
(4)variables.rxcnt[63:0]
|
||||
(5)variables.rxcnt[63:0]
|
||||
(6)variables.rxcnt[63:0]
|
||||
(7)variables.rxcnt[63:0]
|
||||
(8)variables.rxcnt[63:0]
|
||||
(9)variables.rxcnt[63:0]
|
||||
(10)variables.rxcnt[63:0]
|
||||
(11)variables.rxcnt[63:0]
|
||||
(12)variables.rxcnt[63:0]
|
||||
(13)variables.rxcnt[63:0]
|
||||
(14)variables.rxcnt[63:0]
|
||||
(15)variables.rxcnt[63:0]
|
||||
(16)variables.rxcnt[63:0]
|
||||
(17)variables.rxcnt[63:0]
|
||||
(18)variables.rxcnt[63:0]
|
||||
(19)variables.rxcnt[63:0]
|
||||
(20)variables.rxcnt[63:0]
|
||||
(21)variables.rxcnt[63:0]
|
||||
(22)variables.rxcnt[63:0]
|
||||
(23)variables.rxcnt[63:0]
|
||||
(24)variables.rxcnt[63:0]
|
||||
(25)variables.rxcnt[63:0]
|
||||
(26)variables.rxcnt[63:0]
|
||||
(27)variables.rxcnt[63:0]
|
||||
(28)variables.rxcnt[63:0]
|
||||
(29)variables.rxcnt[63:0]
|
||||
(30)variables.rxcnt[63:0]
|
||||
(31)variables.rxcnt[63:0]
|
||||
(32)variables.rxcnt[63:0]
|
||||
(33)variables.rxcnt[63:0]
|
||||
(34)variables.rxcnt[63:0]
|
||||
(35)variables.rxcnt[63:0]
|
||||
(36)variables.rxcnt[63:0]
|
||||
(37)variables.rxcnt[63:0]
|
||||
(38)variables.rxcnt[63:0]
|
||||
(39)variables.rxcnt[63:0]
|
||||
(40)variables.rxcnt[63:0]
|
||||
(41)variables.rxcnt[63:0]
|
||||
(42)variables.rxcnt[63:0]
|
||||
(43)variables.rxcnt[63:0]
|
||||
(44)variables.rxcnt[63:0]
|
||||
(45)variables.rxcnt[63:0]
|
||||
(46)variables.rxcnt[63:0]
|
||||
(47)variables.rxcnt[63:0]
|
||||
(48)variables.rxcnt[63:0]
|
||||
(49)variables.rxcnt[63:0]
|
||||
(50)variables.rxcnt[63:0]
|
||||
(51)variables.rxcnt[63:0]
|
||||
(52)variables.rxcnt[63:0]
|
||||
(53)variables.rxcnt[63:0]
|
||||
(54)variables.rxcnt[63:0]
|
||||
(55)variables.rxcnt[63:0]
|
||||
(56)variables.rxcnt[63:0]
|
||||
(57)variables.rxcnt[63:0]
|
||||
(58)variables.rxcnt[63:0]
|
||||
(59)variables.rxcnt[63:0]
|
||||
(60)variables.rxcnt[63:0]
|
||||
(61)variables.rxcnt[63:0]
|
||||
(62)variables.rxcnt[63:0]
|
||||
(63)variables.rxcnt[63:0]
|
||||
@1401200
|
||||
-group_end
|
||||
@28
|
||||
[color] 1
|
||||
functions.eNB_tx
|
||||
functions.eNB_tx_sleep
|
||||
[color] 7
|
||||
functions.trx_read
|
||||
@24
|
||||
variables.txcnt[63:0]
|
||||
variables.rx_ts[63:0]
|
||||
variables.tx_ts[63:0]
|
||||
variables.pck_rx[63:0]
|
||||
variables.hw_cnt_rx[63:0]
|
||||
variables.lhw_cnt_rx[63:0]
|
||||
variables.hw_frame[63:0]
|
||||
@28
|
||||
functions.eNB_tm
|
||||
@29
|
||||
functions.eNB_trx
|
||||
[pattern_trace] 1
|
||||
[pattern_trace] 0
|
||||
@@ -0,0 +1,540 @@
|
||||
|
||||
/*******************************************************************************
|
||||
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 rrh_gw.h
|
||||
* \brief top-level for the remote radio head gateway (RRH_gw) module reusing the ethernet library
|
||||
* \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning very experimental
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "rrh_gw.h" // change to rrh_new.h, put externs in rrh_extern.h
|
||||
#include "rt_wrapper.h"
|
||||
|
||||
|
||||
#include "log_if.h"
|
||||
#include "log_extern.h"
|
||||
#include "vcd_signal_dumper.h"
|
||||
|
||||
//#undef LOWLATENCY
|
||||
|
||||
/******************************************************************************
|
||||
** FUNCTION PROTOTYPES **
|
||||
******************************************************************************/
|
||||
static void debug_init(void);
|
||||
static void get_options(int argc, char *argv[]);
|
||||
static void print_help(void);
|
||||
static void get_RFinterfaces(void);
|
||||
static rrh_module_t new_module(unsigned int id, dev_type_t type);
|
||||
|
||||
|
||||
char rrh_ip[20] = "192.168.12.31"; // there is code to detect the my ip address
|
||||
int rrh_port = 50000; // has to be an option
|
||||
|
||||
/* log */
|
||||
int16_t glog_level = LOG_DEBUG;
|
||||
int16_t glog_verbosity = LOG_MED;
|
||||
int16_t rrh_log_level = LOG_INFO;
|
||||
int16_t rrh_log_verbosity = LOG_MED;
|
||||
int16_t enb_log_level = LOG_INFO;
|
||||
int16_t enb_log_verbosity = LOG_MED;
|
||||
int16_t ue_log_level = LOG_INFO;
|
||||
int16_t ue_log_verbosity = LOG_MED;
|
||||
|
||||
|
||||
/* flags definitions */
|
||||
uint8_t eNB_flag=0;
|
||||
uint8_t UE_flag=0;
|
||||
uint8_t EXMIMO_flag=0;
|
||||
uint8_t USRP_flag=0;
|
||||
uint8_t RT_flag=0, NRT_flag=1;
|
||||
uint8_t rrh_exit=0;
|
||||
|
||||
/* Default operation as RRH:
|
||||
- there are no eNB nor UE modules
|
||||
- no RF device is asscociated with RRH */
|
||||
uint8_t num_eNB_mod=0;
|
||||
uint8_t num_UE_mod=0;
|
||||
uint8_t num_EXMIMO_mod=0;
|
||||
uint8_t num_USRP_mod=0;
|
||||
uint8_t loopback_flag=0;
|
||||
uint8_t measurements_flag=0;
|
||||
uint8_t hardware_target=NONE_IF;
|
||||
|
||||
unsigned int RT_period=0;
|
||||
rrh_module_t *enb_array,*ue_array;
|
||||
pthread_mutex_t timer_mutex;
|
||||
openair0_vtimestamp hw_counter=0;
|
||||
|
||||
unsigned int rt_period;
|
||||
|
||||
struct itimerspec timerspec;
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
unsigned int i;
|
||||
|
||||
/* parse input arguments */
|
||||
get_options(argc, argv);
|
||||
/* initialize logger and signal analyzer */
|
||||
debug_init();
|
||||
|
||||
set_latency_target();
|
||||
/*make a graceful exit when ctrl-c is pressed */
|
||||
signal(SIGSEGV, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
//probe RF front end devices interfaced to RRH
|
||||
//get_RFinterfaces();
|
||||
|
||||
/* create modules based on input arguments */
|
||||
if (eNB_flag==1){
|
||||
|
||||
enb_array=(rrh_module_t*)malloc(num_eNB_mod*sizeof(rrh_module_t));
|
||||
// create num of modules
|
||||
for(i=0;i<num_eNB_mod;i++){
|
||||
/*
|
||||
enb_array[i]=new_module(i, get_RF_interfaces(&hardware_target));
|
||||
*/
|
||||
enb_array[i]=new_module(i, NONE_IF);
|
||||
create_eNB_trx_threads(&enb_array[i],RT_flag,NRT_flag);
|
||||
LOG_I(RRH,"[eNB %d] module(s) created (%u) \n",i,num_eNB_mod);
|
||||
}
|
||||
|
||||
}
|
||||
if (UE_flag==1){
|
||||
|
||||
ue_array=(rrh_module_t*)malloc(num_UE_mod*sizeof(rrh_module_t));
|
||||
// create num of modules
|
||||
for(i=0;i<num_UE_mod;i++){
|
||||
ue_array[i]=new_module(i, NONE_IF);
|
||||
create_UE_trx_threads(&ue_array[i],RT_flag,NRT_flag);
|
||||
LOG_I(RRH,"[UE %d] module(s) created (%u)\n",i, num_UE_mod);
|
||||
}
|
||||
}
|
||||
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
|
||||
while (rrh_exit==0)
|
||||
sleep(1);
|
||||
|
||||
//close sockets
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*!\fn openair0_device new_module (unsigned int id, dev_type_t type)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static rrh_module_t new_module (unsigned int id, dev_type_t type) {
|
||||
|
||||
rrh_module_t rrh_mod;
|
||||
openair0_config_t openair0_cfg;
|
||||
|
||||
rrh_mod.id=id;
|
||||
rrh_mod.loopback=loopback_flag;
|
||||
rrh_mod.measurements=measurements_flag;
|
||||
rrh_mod.eth_dev.func_type=RRH_FUNC;
|
||||
/* each module is associated with an ethernet device */
|
||||
rrh_mod.eth_dev.type=ETH_IF;
|
||||
openair0_cfg.my_ip=&rrh_ip[0];
|
||||
openair0_cfg.my_port=rrh_port;
|
||||
|
||||
//printf("rrh ip %s\n", rrh_mod.eth_dev.openair0_cfg.my_ip);
|
||||
/* ethernet device initialization*/
|
||||
if (openair0_dev_init_eth(&rrh_mod.eth_dev, &openair0_cfg)<0){
|
||||
LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* initialize another HW device */
|
||||
switch(type){
|
||||
case ETH_IF:
|
||||
LOG_E(RRH,"Error: one module is associated with one ETHERNET iterface!\n");
|
||||
break;
|
||||
case EXMIMO_IF:
|
||||
rrh_mod.devs=malloc(sizeof(openair0_device));
|
||||
rrh_mod.devs->type=EXMIMO_IF;
|
||||
LOG_I(RRH,"Setting RF interface to EXMIMO_IF and initializing device ...\n");
|
||||
/*if (openair0_device_init(rrh_mod.devs, &openair0_cfg)<0){
|
||||
printf("Exiting, cannot initialize device.\n");
|
||||
exit(-1);
|
||||
}*/
|
||||
break;
|
||||
case USRP_IF:
|
||||
rrh_mod.devs=malloc(sizeof(openair0_device));
|
||||
rrh_mod.devs->type=USRP_IF;
|
||||
LOG_I(RRH,"Setting RF interface to USRP_IF and initializing device ...\n");
|
||||
/*if (openair0_device_init(rrh_mod.devs, &openair0_cfg)<0){
|
||||
printf("Exiting, cannot initialize device.\n");
|
||||
exit(-1);
|
||||
} */
|
||||
break;
|
||||
case BLADERF_IF:
|
||||
rrh_mod.devs=malloc(sizeof(openair0_device));
|
||||
rrh_mod.devs->type=BLADERF_IF;
|
||||
LOG_I(RRH,"Setting RF interface to BLADERF_IF and initializing device ...\n");
|
||||
/* if (openair0_device_init(rrh_mod.devs, &openair0_cfg)<0){
|
||||
printf("Exiting, cannot initialize device.\n");
|
||||
exit(-1);
|
||||
} */
|
||||
break;
|
||||
case NONE_IF:
|
||||
rrh_mod.devs=NULL;
|
||||
LOG_I(RRH,"Setting RF interface to NONE_IF... \n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return rrh_mod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! \fn static void get_RFinterfaces(void)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static void get_RFinterfaces(void) {
|
||||
|
||||
//tbd
|
||||
EXMIMO_flag=1;
|
||||
USRP_flag=1;
|
||||
num_EXMIMO_mod=1;
|
||||
num_USRP_mod=1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!\fn void create_timer_thread(void)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void create_timer_thread() {
|
||||
|
||||
int error_code_timer;
|
||||
pthread_t main_timer_proc_thread;
|
||||
|
||||
LOG_I(RRH,"Creating timer thread with rt period %d ns.\n",rt_period);
|
||||
|
||||
/* setup the timer to generate an interrupt:
|
||||
-for the first time in (sample_per_packet/sample_rate) ns
|
||||
-and then every (sample_per_packet/sample_rate) ns */
|
||||
timerspec.it_value.tv_sec = rt_period/1000000000;
|
||||
timerspec.it_value.tv_nsec = rt_period%1000000000;
|
||||
timerspec.it_interval.tv_sec = rt_period/1000000000;
|
||||
timerspec.it_interval.tv_nsec = rt_period%1000000000;
|
||||
|
||||
pthread_mutex_init(&timer_mutex,NULL);
|
||||
|
||||
#ifndef LOWLATENCY
|
||||
pthread_attr_t attr_timer;
|
||||
struct sched_param sched_param_timer;
|
||||
|
||||
pthread_attr_init(&attr_timer);
|
||||
sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-1);
|
||||
pthread_attr_setschedparam(&attr_timer,&sched_param_timer);
|
||||
pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-1);
|
||||
error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec);
|
||||
LOG_D(RRH,"[SCHED] FIFO scheduling \n");
|
||||
#else
|
||||
error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec);
|
||||
LOG_D(RRH,"[SCHED] LOWLATENCY scheduling \n");
|
||||
#endif
|
||||
|
||||
if (error_code_timer) {
|
||||
LOG_E(RRH,"Error while creating timer proc thread\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void *timer_proc(void *arg)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void *timer_proc(void *arg) {
|
||||
|
||||
timer_t timerid; // timer ID for timer
|
||||
struct itimerspec *timer = (struct itimerspec*)arg; // the timer data structure
|
||||
struct itimerspec *old_value;
|
||||
|
||||
LOG_I(RRH,"timer thread created\n");
|
||||
|
||||
|
||||
#ifdef LOWLATENCY
|
||||
struct sched_attr attr;
|
||||
unsigned int flags = 0;
|
||||
|
||||
attr.size = sizeof(attr);
|
||||
attr.sched_flags = 0;
|
||||
attr.sched_nice = 0;
|
||||
attr.sched_priority = 0;
|
||||
|
||||
attr.sched_policy = SCHED_DEADLINE;
|
||||
attr.sched_runtime = (0.1 * 100) * 10000; //
|
||||
attr.sched_deadline = rt_period;//(0.1 * 100) * 10000; //
|
||||
attr.sched_period = rt_period;//(0.1 * 100) * 10000; // each TX/RX thread has, as a function of RT PERIOD ??
|
||||
|
||||
if (sched_setattr(0, &attr, flags) < 0 ) {
|
||||
perror("[SCHED] timer thread: sched_setattr failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
//printf("Starting the timer\n");
|
||||
if (timer_create (CLOCK_REALTIME, NULL, &timerid) == -1) {
|
||||
fprintf (stderr, "couldn't create a timer\n");
|
||||
perror (NULL);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signal(SIGALRM, timer_signal_handler);
|
||||
// and start it!
|
||||
timer_settime (timerid, 0, timer, old_value);
|
||||
//timer_settime (timerid, TIMER_ABSTIME, timer, old_value);
|
||||
|
||||
while (!rrh_exit) {
|
||||
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TM, 1 );
|
||||
sleep(1);
|
||||
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TM, 0 );
|
||||
}
|
||||
|
||||
timer_delete(timerid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void timer_signal_handler(int sig)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void timer_signal_handler(int sig) {
|
||||
|
||||
if (sig == SIGALRM) {
|
||||
pthread_mutex_lock(&timer_mutex);
|
||||
hw_counter ++;
|
||||
pthread_mutex_unlock(&timer_mutex);
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, hw_counter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void signal_handler(int sig)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
void signal_handler(int sig) {
|
||||
|
||||
void *array[10];
|
||||
size_t size;
|
||||
|
||||
if (sig==SIGSEGV) {
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, 10);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "Error: signal %d:\n", sig);
|
||||
backtrace_symbols_fd(array, size, 2);
|
||||
exit(-1);
|
||||
} else {
|
||||
printf("trying to exit gracefully...\n");
|
||||
rrh_exit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \fn void debug_init(void)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static void debug_init(void) {
|
||||
|
||||
// log initialization
|
||||
logInit();
|
||||
set_glog(glog_level, glog_verbosity);
|
||||
|
||||
set_comp_log(RRH, rrh_log_level, rrh_log_verbosity, 1);
|
||||
//set_comp_log(ENB_LOG, enb_log_level, enb_log_verbosity, 1);
|
||||
//set_comp_log(UE_LOG, ue_log_level, ue_log_verbosity, 1);
|
||||
|
||||
// vcd initialization
|
||||
if (ouput_vcd) {
|
||||
|
||||
if (eNB_flag==1)
|
||||
vcd_signal_dumper_init("/tmp/openair_dump_eNB.vcd");
|
||||
if (UE_flag==1)
|
||||
vcd_signal_dumper_init("/tmp/openair_dump_UE.vcd");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!\fn void get_options(int argc, char *argv[])
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static void get_options(int argc, char *argv[]) {
|
||||
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "xvhlte:n:u:g:r:w:")) != -1) {
|
||||
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
eNB_flag=1;
|
||||
num_eNB_mod=atoi(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
UE_flag=1;
|
||||
num_UE_mod=atoi(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
glog_level=atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
//rrh_log_level=atoi(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
//enb_log_level=atoi(optarg);
|
||||
break;
|
||||
case 'x':
|
||||
rt_period = DEFAULT_PERIOD_NS;
|
||||
RT_flag=1;
|
||||
NRT_flag=0;
|
||||
break;
|
||||
case 'v':
|
||||
/* extern from vcd */
|
||||
ouput_vcd=1;
|
||||
break;
|
||||
case 'l':
|
||||
/*In loopback mode rrh sends back to bbu what it receives*/
|
||||
loopback_flag=1;
|
||||
break;
|
||||
case 't':
|
||||
/*When measurements are enabled statistics related to TX/RX time are printed*/
|
||||
measurements_flag=1;
|
||||
break;
|
||||
case 'w':
|
||||
/* force to use this target*/
|
||||
//hardware_target=
|
||||
break;
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(-1);
|
||||
default: /* '?' */
|
||||
//fprintf(stderr, "Usage: \n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!\fn void print_help(void)
|
||||
* \brief this function
|
||||
* \param[in]
|
||||
* \param[out]
|
||||
* \return
|
||||
* \note
|
||||
* @ingroup _oai
|
||||
*/
|
||||
static void print_help(void) {
|
||||
|
||||
puts("Usage: \n");
|
||||
puts(" sudo -E chrt 99 ./rrh -n1 -g6 -v -t");
|
||||
puts("Options:\n");
|
||||
puts("\t -n create eNB module\n");
|
||||
puts("\t -u create UE module\n");
|
||||
puts("\t -g define global log level\n");
|
||||
puts("\t -r define rrh log level\n");
|
||||
puts("\t -e define eNB log level\n");
|
||||
puts("\t -x enable real time bahaviour\n");
|
||||
puts("\t -v enable vcd dump\n");
|
||||
puts("\t -l enable loopback mode\n");
|
||||
puts("\t -t enable measurements\n");
|
||||
puts("\t -w force to use specified HW\n");
|
||||
puts("\t -h display info\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
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 rrh_gw.h
|
||||
* \brief header file for remote radio head gateway (RRH_gw) module
|
||||
* \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning very experimental
|
||||
*/
|
||||
|
||||
#ifndef RRH_GW_H_
|
||||
#define RRH_GW_H_
|
||||
|
||||
#include "ethernet_lib.h"
|
||||
#include "vcd_signal_dumper.h"
|
||||
#include "assertions.h"
|
||||
|
||||
#define DEFAULT_PERIOD_NS 200000
|
||||
#define RRH_UE_PORT 51000
|
||||
#define RRH_UE_DEST_IP "127.0.0.1"
|
||||
|
||||
/*! \brief RRH supports two types of modules: eNB and UE
|
||||
each module is associated a device of type ETH_IF
|
||||
and optionally with another device (USRP/BLADERF/EXMIMO) */
|
||||
typedef struct {
|
||||
//! module id
|
||||
uint8_t id;
|
||||
//! loopback flag
|
||||
uint8_t loopback;
|
||||
//! measurement flag
|
||||
uint8_t measurements;
|
||||
//! module's ethernet device
|
||||
openair0_device eth_dev;
|
||||
//! pointer to RF module's device (pointer->since its optional)
|
||||
openair0_device *devs;
|
||||
|
||||
}rrh_module_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** FUNCTION PROTOTYPES **
|
||||
******************************************************************************/
|
||||
void signal_handler(int sig);
|
||||
void timer_signal_handler(int);
|
||||
void *timer_proc(void *);
|
||||
void create_timer_thread(void);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** FUNCTION PROTOTYPES **
|
||||
******************************************************************************/
|
||||
void create_UE_trx_threads( rrh_module_t *dev_ue, uint8_t RT_flag, uint8_t NRT_flag);
|
||||
void create_eNB_trx_threads( rrh_module_t *dev_enb, uint8_t RT_flag, uint8_t NRT_flag);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
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 rrh_gw_extern.h
|
||||
* \brief rrh gatewy external vars
|
||||
* \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp
|
||||
* \date 2015
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \maintainer: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning very experimental
|
||||
*/
|
||||
|
||||
#ifndef RRH_GW_EXTERNS_H_
|
||||
#define RRH_GW_EXTERNS_H_
|
||||
|
||||
extern openair0_timestamp timestamp_UE_tx[4] ,timestamp_UE_rx[4] ,timestamp_eNB_rx[4],timestamp_eNB_tx[4];
|
||||
extern openair0_vtimestamp hw_counter;
|
||||
extern int32_t UE_tx_started,UE_rx_started,eNB_rx_started ,eNB_tx_started;
|
||||
extern int32_t nsamps_UE[4],nsamps_eNB[4];
|
||||
extern int32_t overflow_rx_buffer_eNB[4],overflow_rx_buffer_UE[4];
|
||||
extern uint8_t rrh_exit;
|
||||
extern int32_t **rx_buffer_eNB, **rx_buffer_UE;
|
||||
|
||||
extern unsigned int rt_period;
|
||||
|
||||
#endif
|
||||
@@ -28,17 +28,51 @@
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file rt_wrapper.h
|
||||
* \brief provides a wrapper for the timing function for real-time opeartions depending on weather RTAI is used or not
|
||||
* \author F. Kaltenberger
|
||||
* \brief provides a wrapper for the timing function, runtime calculations for real-time opeartions depending on weather RTAI or LOWLATENCY kernels are used or not
|
||||
* \author F. Kaltenberger and Navid Nikaein
|
||||
* \date 2013
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \email: florian.kaltenberger@eurecom.fr
|
||||
* \email: florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include "rt_wrapper.h"
|
||||
static int latency_target_fd = -1;
|
||||
static int32_t latency_target_value = 0;
|
||||
/* Latency trick - taken from cyclictest.c
|
||||
* if the file /dev/cpu_dma_latency exists,
|
||||
* open it and write a zero into it. This will tell
|
||||
* the power management system not to transition to
|
||||
* a high cstate (in fact, the system acts like idle=poll)
|
||||
* When the fd to /dev/cpu_dma_latency is closed, the behavior
|
||||
* goes back to the system default.
|
||||
*
|
||||
* Documentation/power/pm_qos_interface.txt
|
||||
*/
|
||||
void set_latency_target(void) {
|
||||
struct stat s;
|
||||
int ret;
|
||||
|
||||
if (stat("/dev/cpu_dma_latency", &s) == 0) {
|
||||
latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR);
|
||||
|
||||
if (latency_target_fd == -1)
|
||||
return;
|
||||
|
||||
ret = write(latency_target_fd, &latency_target_value, 4);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno));
|
||||
close(latency_target_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef RTAI
|
||||
|
||||
@@ -89,6 +123,135 @@ void check_clock(void)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t cell_processing_dl[6]={10,15,24,42,80,112};
|
||||
uint16_t platform_processing_dl=20; // upperbound for GPP, LXC, DOCKER and KVM
|
||||
uint16_t user_processing_dl_a[6]={2,4,5,7,10,12};
|
||||
uint16_t user_processing_dl_b[6]={10, 15, 25, 70, 110, 150};
|
||||
uint16_t user_processing_dl_err[6]={20, 40, 60, 90, 120, 160};
|
||||
uint16_t protocol_processing_dl[6]={150, 250, 350, 450, 650, 800}; // assumption: max MCS 27 --> gives an upper bound for the transport block size : to be measured
|
||||
|
||||
uint16_t cell_processing_ul[6]={10,15,24,42,80,112};
|
||||
uint16_t platform_processing_ul=30; // upperbound for GPP, LXC, DOCKER and KVM
|
||||
uint16_t user_processing_ul_a[6]={5, 9, 12, 24, 33, 42};
|
||||
uint16_t user_processing_ul_b[6]={20, 30, 40, 76, 140, 200};
|
||||
uint16_t user_processing_ul_err[6]={15, 25, 32, 60, 80, 95};
|
||||
uint16_t protocol_processing_ul[6]={100, 200, 300, 400, 550, 700}; // assumption: max MCS 16 --> gives an upper bound for the transport block size
|
||||
|
||||
int fill_modeled_runtime_table(uint16_t runtime_phy_rx[29][6],
|
||||
uint16_t runtime_phy_tx[29][6]){
|
||||
//double cpu_freq;
|
||||
//cpu_freq = get_cpu_freq_GHz();
|
||||
// target_dl_mcs
|
||||
// target_ul_mcs
|
||||
// frame_parms[0]->N_RB_DL
|
||||
int i,j;
|
||||
memset(runtime_phy_rx,0,sizeof(uint16_t)*29*6);
|
||||
memset(runtime_phy_tx,0,sizeof(uint16_t)*29*6);
|
||||
/* only the BBU/PHY procesing time */
|
||||
for (i=0;i<29;i++){
|
||||
for (j=0;j<6;j++){
|
||||
runtime_phy_rx[i][j] = cell_processing_ul[j] + platform_processing_ul + user_processing_ul_err[j] + user_processing_ul_a[j]*i+ user_processing_ul_b[j];
|
||||
runtime_phy_tx[i][j] = cell_processing_dl[j] + platform_processing_dl + user_processing_dl_err[j] + user_processing_dl_a[j]*i+ user_processing_dl_b[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// int runtime_upper_layers[6]; // values for different RBs
|
||||
// int runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
|
||||
// int runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
|
||||
|
||||
// target_dl_mcs
|
||||
// target_ul_mcs
|
||||
// frame_parms[0]->N_RB_DL
|
||||
//runtime_upper_layers[6]; // values for different RBs
|
||||
// int runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
|
||||
// int runtime_phy_tx[29][6]
|
||||
|
||||
double get_runtime_tx(int tx_subframe, uint16_t runtime_phy_tx[29][6], uint32_t mcs, int N_RB_DL,double cpuf,int nb_tx_antenna){
|
||||
int i;
|
||||
double runtime;
|
||||
//printf("cpuf =%lf \n",cpuf);
|
||||
switch(N_RB_DL){
|
||||
case 6:
|
||||
i = 0;
|
||||
break;
|
||||
case 15:
|
||||
i = 1;
|
||||
break;
|
||||
case 25:
|
||||
i = 2;
|
||||
break;
|
||||
case 50:
|
||||
i = 3;
|
||||
break;
|
||||
case 75:
|
||||
i = 4;
|
||||
break;
|
||||
case 100:
|
||||
i = 5;
|
||||
break;
|
||||
default:
|
||||
i = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
runtime = ( (3.2/cpuf)*(double)runtime_phy_tx[mcs][i] + (3.2/cpuf)*(double)protocol_processing_dl[i])/1000 ;
|
||||
printf("Setting tx %d runtime value (ms) = %lf\n",tx_subframe,runtime);
|
||||
|
||||
return runtime;
|
||||
}
|
||||
|
||||
double get_runtime_rx(int rx_subframe, uint16_t runtime_phy_rx[29][6], uint32_t mcs, int N_RB_DL,double cpuf,int nb_rx_antenna){
|
||||
int i;
|
||||
double runtime;
|
||||
|
||||
//printf("N_RB_DL=%d cpuf =%lf \n",N_RB_DL, cpuf);
|
||||
switch(N_RB_DL){
|
||||
case 6:
|
||||
i = 0;
|
||||
break;
|
||||
case 15:
|
||||
i = 1;
|
||||
break;
|
||||
case 25:
|
||||
i = 2;
|
||||
break;
|
||||
case 50:
|
||||
i = 3;
|
||||
break;
|
||||
case 75:
|
||||
i = 4;
|
||||
break;
|
||||
case 100:
|
||||
i = 5;
|
||||
break;
|
||||
default:
|
||||
i = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
runtime = ((3.2/cpuf)*(double)runtime_phy_rx[mcs][i] + (3.2/cpuf)*(double)protocol_processing_ul[i])/1000 ;
|
||||
printf("Setting rx %d runtime value (ms) = %lf \n",rx_subframe, runtime);
|
||||
|
||||
return runtime;
|
||||
}
|
||||
|
||||
#ifdef LOWLATENCY
|
||||
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
|
||||
{
|
||||
|
||||
return syscall(__NR_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
|
||||
|
||||
int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned int flags)
|
||||
{
|
||||
|
||||
return syscall(__NR_sched_getattr, pid, attr, size, flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int rt_sleep_ns(RTIME x)
|
||||
|
||||
@@ -38,13 +38,20 @@
|
||||
* \warning This code will be removed when a legacy libc API becomes available.
|
||||
*/
|
||||
|
||||
|
||||
void set_latency_target(void);
|
||||
|
||||
#ifndef RTAI
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <syscall.h>
|
||||
#include <math.h>
|
||||
|
||||
#define RTIME long long int
|
||||
|
||||
@@ -56,6 +63,11 @@ int rt_sleep_ns (RTIME x);
|
||||
|
||||
void check_clock(void);
|
||||
|
||||
int fill_modeled_runtime_table(uint16_t runtime_phy_rx[29][6],uint16_t runtime_phy_tx[29][6]);
|
||||
|
||||
double get_runtime_tx(int tx_subframe, uint16_t runtime_phy_tx[29][6],uint32_t mcs, int N_RB_DL,double cpuf,int nb_tx_antenna);
|
||||
|
||||
double get_runtime_rx(int rx_subframe, uint16_t runtime_phy_rx[29][6], uint32_t mcs, int N_RB_DL,double cpuf,int nb_rx_antenna);
|
||||
/**
|
||||
* see https://www.kernel.org/doc/Documentation/scheduler/sched-deadline.txt or
|
||||
* http://www.blaess.fr/christophe/2014/04/05/utiliser-un-appel-systeme-inconnu-de-la-libc/
|
||||
|
||||
Reference in New Issue
Block a user