Commit caed02a8 authored by bruno mongazon's avatar bruno mongazon

Fix #582, ENABLE_PGM_TRANSPORT removed, RRH related removed

parent 18fffbf1
......@@ -608,12 +608,6 @@ add_boolean_option(FLEXRAN_AGENT_SB_IF False "enable FlexRAN
##########################
add_boolean_option(ENB_MODE True "Swap the include directories between openair2 and openair3" )
##########################
# Emulation options
##########################
add_boolean_option(ENABLE_PGM_TRANSPORT False "specific to oaisim, emulation through ethernet, reliable multicast")
add_boolean_option(ADDR_CONF False "specific to oaisim, IP autoconf of user-plane IP interface")
##########################
# SCHEDULING/REAL-TIME/PERF options
##########################
......@@ -1595,7 +1589,6 @@ ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/socket.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c
#${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/emu_transport.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/pgm_link.c
)
add_library(OPENAIR0_LIB
......@@ -1812,27 +1805,6 @@ target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt
target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES})
target_link_libraries (lte-softmodem-nos1 ${T_LIB})
# rrh
################################
#Note: only one RF type (USRP) 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/COMMON/common_lib.c
${T_SOURCE}
)
target_include_directories(rrh_gw PRIVATE ${OPENAIR_DIR}/common/utils/itti)
target_link_libraries(rrh_gw
-Wl,--start-group
UTIL LFDS -ldl
-Wl,--end-group )
target_link_libraries (rrh_gw rt pthread m )
target_link_libraries (rrh_gw ${LIB_LMS_LIBRARIES})
target_link_libraries (rrh_gw ${T_LIB})
# USIM process
#################
#add_executable(usim
......@@ -2047,7 +2019,7 @@ endforeach(myExe)
if (${T_TRACER})
foreach(i
#all "add_executable" definitions (except tests, rb_tool, updatefw)
lte-softmodem lte-softmodem-nos1 rrh_gw oaisim oaisim_nos1
lte-softmodem lte-softmodem-nos1 oaisim oaisim_nos1
dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim
pdcchsim pucchsim prachsim syncsim
#all "add_library" definitions
......
......@@ -100,8 +100,6 @@ Options
Specify conf_nvram_path (default \"$conf_nvram_path\")
--UE-gen-nvram [output path]
Specify gen_nvram_path (default \"$gen_nvram_path\")
--RRH
Makes the RRH
-a | --agent
Enables agent for software-defined control of the eNB
-r | --3gpp-release
......@@ -219,10 +217,6 @@ function main() {
--UE-gen-nvram)
gen_nvram_path=$(readlink -f $2)
shift 2;;
--RRH)
RRH=1
echo_info "Will compile RRH"
shift;;
-r | --3gpp-release)
REL=$2
echo_info "Setting release to: $REL"
......@@ -371,7 +365,7 @@ function main() {
echo_info "CMAKE_CMD=$CMAKE_CMD"
#########################################################
# check validity of HW and TP parameters for RRH and eNB
# check validity of HW and TP parameters for eNB
#########################################################
# to be discussed
......@@ -387,15 +381,6 @@ function main() {
fi
fi
if [ "$RRH" = "1" ] ; then
if [ "$TP" = "None" ] ; then
echo_fatal "A transport protocol (e.g. -t ETHERNET) must be defined!"
fi
if [ "$HW" = "None" ] ; then
echo_info "No radio head has been selected (HW set to $HW)"
fi
fi
echo_info "RF HW set to $HW"
#Now we set flags to enable deadline scheduler settings
#By default: USRP: disable,
......@@ -793,36 +778,6 @@ function main() {
# oaisim_mme $dbin/oaisim_mme.$REL
fi
# RRH compilation
#####################
if [ "$RRH" = "1" ] ; then
rrh_exec=rrh_gw
rrh_build_dir=rrh_gw
echo_info "Compiling $rrh_exec ..."
[ "$CLEAN" = "1" ] && rm -rf $DIR/rrh_gw/build
mkdir -p $DIR/$rrh_build_dir/build
cmake_file=$DIR/$rrh_build_dir/CMakeLists.txt
echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file
echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $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 ( TRANSP_PRO \"${TP}\")" >> $cmake_file
echo 'set ( PACKAGE_NAME "\"rrh_gw\"")' >> $cmake_file
echo "set ( DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file
echo "set ( CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file
echo "set ( T_TRACER $T_TRACER )" >> $cmake_file
echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file
cd $DIR/$rrh_build_dir/build
eval $CMAKE_CMD
compilations \
rrh_gw rrh_gw \
rrh_gw $dbin/rrh_gw
fi
# Telnet server compilation
#####################
if [ "$BUILD_TELNETSRV" = "1" ] ; then
......@@ -841,13 +796,9 @@ function main() {
fi
# build RF device and transport protocol libraries
#####################################
if [ "$eNB" = "1" -o "$UE" = "1" -o "$RRH" = "1" ] ; then
if [ "$eNB" = "1" -o "$UE" = "1" ] ; then
build_dir=$lte_build_dir
else
build_dir=$rrh_build_dir
fi
# build RF device libraries
if [ "$HW" != "None" ] ; then
......
......@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 2.8)
set ( CMAKE_BUILD_TYPE "RelWithDebInfo" )
set ( ASN_DEBUG False)
set ( ADDR_CONF False )
set ( DEBUG_OMG False )
set ( DISABLE_XER_PRINT False )
set ( DRIVER2013 True )
......@@ -11,7 +10,6 @@ set ( ENABLE_FXP True )
set ( ENABLE_ITTI True )
set ( ENABLE_NAS_UE_LOGGING True )
set ( ENABLE_NEW_MULTICAST True )
set ( ENABLE_PGM_TRANSPORT True )
set ( ENABLE_SECURITY True )
set ( ENABLE_STANDALONE_EPC False)
set ( ENABLE_USE_CPU_EXECUTION_TIME True )
......
cmake_minimum_required(VERSION 2.8)
set ( CMAKE_BUILD_TYPE "RelWithDebInfo" )
set ( ADDR_CONF False )
set ( DEBUG_OMG False )
set ( DISABLE_XER_PRINT False )
set ( DRIVER2013 True )
......@@ -9,7 +8,6 @@ set ( ENABLE_FXP True )
set ( ENABLE_ITTI True )
set ( ENABLE_NAS_UE_LOGGING True )
set ( ENABLE_NEW_MULTICAST True )
set ( ENABLE_PGM_TRANSPORT True )
set ( ENABLE_RAL False )
set ( ENABLE_SECURITY True )
set ( ENABLE_STANDALONE_EPC False)
......
cmake_minimum_required(VERSION 2.8)
set ( CMAKE_BUILD_TYPE "RelWithDebInfo" )
set ( ADDR_CONF False )
set ( DEBUG_OMG False )
set ( DISABLE_XER_PRINT False )
set ( DRIVER2013 False )
......@@ -9,7 +8,6 @@ set ( ENABLE_FXP False )
set ( ENABLE_ITTI True )
set ( ENABLE_NAS_UE_LOGGING False )
set ( ENABLE_NEW_MULTICAST False )
set ( ENABLE_PGM_TRANSPORT False )
set ( ENABLE_RAL False )
set ( ENABLE_SECURITY False )
set ( ENABLE_STANDALONE_EPC False )
......
cmake_minimum_required(VERSION 2.8)
set ( ADDR_CONF False )
set ( DEBUG_OMG False )
set ( DISABLE_XER_PRINT False )
set ( DRIVER2013 True )
......@@ -8,7 +7,6 @@ set ( ENABLE_FXP True )
set ( ENABLE_ITTI True )
set ( ENABLE_NAS_UE_LOGGING False )
set ( ENABLE_NEW_MULTICAST True )
set ( ENABLE_PGM_TRANSPORT True )
set ( ENABLE_RAL False )
set ( ENABLE_SECURITY False )
set ( ENABLE_STANDALONE_EPC False)
......
cmake_minimum_required(VERSION 2.8)
set ( CMAKE_BUILD_TYPE "RelWithDebInfo" )
set ( ADDR_CONF False )
set ( DEBUG_OMG False )
set ( DISABLE_XER_PRINT False )
set ( DRIVER2013 True )
......@@ -10,7 +9,6 @@ set ( ENABLE_ITTI True )
set ( ENABLE_NAS_UE_LOGGING True )
set ( ENABLE_NEW_MULTICAST True )
set ( ENABLE_PDCP_NETLINK_FIFO False )
set ( ENABLE_PGM_TRANSPORT True )
set ( ENABLE_RAL False )
set ( ENABLE_SECURITY True )
set ( ENABLE_STANDALONE_EPC False)
......
......@@ -39,7 +39,6 @@
#include "UTIL/LOG/log.h"
#include "multicast_link.h"
#include "pgm_link.h"
char rx_bufferP[BYPASS_RX_BUFFER_SIZE];
unsigned int num_bytesP = 0;
......@@ -49,10 +48,6 @@ static unsigned int byte_tx_count;
unsigned int Master_list_rx;
static uint64_t seq_num_tx = 0;
#if defined(ENABLE_PGM_TRANSPORT)
extern unsigned int pgm_would_block;
#endif
mapping transport_names[] = {
{"WAIT PM TRANSPORT INFO", EMU_TRANSPORT_INFO_WAIT_PM},
{"WAIT SM TRANSPORT INFO", EMU_TRANSPORT_INFO_WAIT_SM},
......@@ -60,9 +55,6 @@ mapping transport_names[] = {
{"ENB_TRANSPORT INFO", EMU_TRANSPORT_INFO_ENB},
{"UE TRANSPORT INFO", EMU_TRANSPORT_INFO_UE},
{"RELEASE TRANSPORT INFO", EMU_TRANSPORT_INFO_RELEASE},
#if defined(ENABLE_PGM_TRANSPORT)
{"NACK TRANSPORT INFO", EMU_TRANSPORT_NACK},
#endif
{NULL, -1}
};
......@@ -77,9 +69,6 @@ void init_bypass (void)
pthread_mutex_init (&emul_low_mutex, NULL);
pthread_cond_init (&emul_low_cond, NULL);
emul_low_mutex_var = 1;
#endif
#if defined(ENABLE_PGM_TRANSPORT)
pgm_oai_init(oai_emulation.info.multicast_ifname);
#endif
bypass_init (emul_tx_handler, emul_rx_handler);
}
......@@ -318,20 +307,12 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot,
frame, next_slot, is_master);
#if defined(ENABLE_NEW_MULTICAST)
# if defined(ENABLE_PGM_TRANSPORT)
num_bytesP = pgm_recv_msg(oai_emulation.info.multicast_group,
(uint8_t *)&rx_bufferP[0], sizeof(rx_bufferP),
frame, next_slot);
DevCheck(num_bytesP > 0, num_bytesP, 0, 0);
# else
if (multicast_link_read_data_from_sock(is_master) == 1) {
/* We got a timeout */
return -1;
}
# endif
#else
pthread_mutex_lock(&emul_low_mutex);
......@@ -359,10 +340,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot,
num_bytesP, map_int_to_str(transport_names, messg->Message_type),
messg->master_id,
messg->seq_num);
#if defined(ENABLE_PGM_TRANSPORT)
if (messg->Message_type != EMU_TRANSPORT_NACK)
#endif
DevCheck4((messg->frame == frame) && (messg->subframe == (next_slot>>1)),
messg->frame, frame, messg->subframe, next_slot>>1);
......@@ -405,20 +382,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot,
Master_list_rx = oai_emulation.info.master_list;
LOG_E(EMU, "RX EMU_TRANSPORT_INFO_RELEASE\n");
break;
#if defined(ENABLE_PGM_TRANSPORT)
case EMU_TRANSPORT_NACK:
if (messg->failing_master_id == oai_emulation.info.master_id) {
/* We simply re-send the last message */
pgm_link_send_msg(oai_emulation.info.multicast_group,
(uint8_t *)bypass_tx_buffer, byte_tx_count);
} else {
/* Sleep awhile till other peers have recovered data */
usleep(500);
}
break;
#endif
default:
LOG_E(EMU, "[MAC][BYPASS] ERROR RX UNKNOWN MESSAGE\n");
......@@ -483,13 +446,6 @@ void bypass_signal_mac_phy(unsigned int frame, unsigned int last_slot,
}
}
#if defined(ENABLE_PGM_TRANSPORT)
void bypass_tx_nack(unsigned int frame, unsigned int next_slot)
{
bypass_tx_data(NACK_TRANSPORT, frame, next_slot);
}
#endif
/***************************************************************************/
void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int next_slot)
{
......@@ -519,26 +475,6 @@ void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int
byte_tx_count = sizeof (bypass_msg_header_t) + sizeof (
bypass_proto2multicast_header_t);
#if defined(ENABLE_PGM_TRANSPORT)
if (Type == NACK_TRANSPORT) {
int i;
messg->Message_type = EMU_TRANSPORT_NACK;
for (i = 0; i < oai_emulation.info.nb_master; i++) {
/* Skip our id */
if (i == oai_emulation.info.master_id)
continue;
if ((Master_list_rx & (1 << i)) == 0) {
messg->failing_master_id = i;
break;
}
}
LOG_T(EMU,"[TX_DATA] NACK TRANSPORT\n");
} else
#endif
if (Type == WAIT_PM_TRANSPORT) {
messg->Message_type = EMU_TRANSPORT_INFO_WAIT_PM;
LOG_T(EMU,"[TX_DATA] WAIT SYNC PM TRANSPORT\n");
......@@ -630,13 +566,8 @@ void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int
((bypass_proto2multicast_header_t *) bypass_tx_buffer)->size = byte_tx_count -
sizeof (bypass_proto2multicast_header_t);
#if defined(ENABLE_PGM_TRANSPORT)
pgm_link_send_msg(oai_emulation.info.multicast_group,
(uint8_t *)bypass_tx_buffer, byte_tx_count);
#else
multicast_link_write_sock(oai_emulation.info.multicast_group,
bypass_tx_buffer, byte_tx_count);
#endif
LOG_D(EMU, "Frame %d, subframe %d (%d): Sent %d bytes [%s] with master_id %d and seq %"PRIuMAX"\n",
frame, next_slot>>1, next_slot,byte_tx_count, map_int_to_str(transport_names, Type),
......
......@@ -41,9 +41,6 @@ typedef enum emu_transport_info_e {
EMU_TRANSPORT_INFO_ENB,
EMU_TRANSPORT_INFO_UE,
EMU_TRANSPORT_INFO_RELEASE
#if defined(ENABLE_PGM_TRANSPORT)
,EMU_TRANSPORT_NACK
#endif
} emu_transport_info_t;
#define WAIT_PM_TRANSPORT 1
......@@ -52,9 +49,6 @@ typedef enum emu_transport_info_e {
#define ENB_TRANSPORT 4
#define UE_TRANSPORT 5
#define RELEASE_TRANSPORT 6
#if defined(ENABLE_PGM_TRANSPORT)
# define NACK_TRANSPORT 7
#endif
#define WAIT_SYNC_TRANSPORT 1
#define SYNCED_TRANSPORT 2
......
......@@ -40,49 +40,17 @@
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "pgm_link.h"
extern unsigned int Master_list_rx;
extern unsigned char NB_INST;
//#define DEBUG_CONTROL 1
//#define DEBUG_EMU 1
#if defined(ENABLE_PGM_TRANSPORT)
extern unsigned int pgm_would_block;
#endif
void emu_transport_sync(void)
{
LOG_D(EMU, "Entering EMU transport SYNC is primary master %d\n",
oai_emulation.info.is_primary_master);
#if defined(ENABLE_PGM_TRANSPORT)
if (oai_emulation.info.is_primary_master == 0) {
bypass_tx_data(WAIT_SM_TRANSPORT,0,0);
// just wait to recieve the master 0 msg
Master_list_rx = oai_emulation.info.master_list - 1;
bypass_rx_data(0,0,0,1);
} else {
bypass_rx_data(0,0,0,0);
bypass_tx_data(WAIT_PM_TRANSPORT,0,0);
}
if (oai_emulation.info.master_list != 0) {
bypass_tx_data(SYNC_TRANSPORT,0,0);
bypass_rx_data(0,0,0,0);
// i received the sync from all secondary masters
if (emu_rx_status == SYNCED_TRANSPORT) {
emu_tx_status = SYNCED_TRANSPORT;
}
LOG_D(EMU,"TX secondary master SYNC_TRANSPORT state \n");
}
#else
if (oai_emulation.info.is_primary_master == 0) {
retry:
bypass_tx_data(WAIT_SM_TRANSPORT,0,0);
......@@ -115,8 +83,6 @@ retry2:
LOG_D(EMU,"TX secondary master SYNC_TRANSPORT state \n");
}
#endif
LOG_D(EMU, "Leaving EMU transport SYNC is primary master %d\n",
oai_emulation.info.is_primary_master);
}
......@@ -154,9 +120,6 @@ void emu_transport(unsigned int frame, unsigned int last_slot,
}
}
#if defined(ENABLE_PGM_TRANSPORT)
pgm_would_block = 0;
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(
VCD_SIGNAL_DUMPER_FUNCTIONS_EMU_TRANSPORT, VCD_FUNCTION_OUT);
}
......
......@@ -314,9 +314,7 @@ void multicast_link_start(void (*rx_handlerP) (unsigned int, char *),
LOG_I(EMU, "[MULTICAST] LINK START on interface=%s for group=%d: handler=%p\n",
(multicast_if == NULL) ? "not specified" : multicast_if, multicast_group,
rx_handler);
#if !defined(ENABLE_PGM_TRANSPORT)
multicast_link_init ();
#endif
#if ! defined(ENABLE_NEW_MULTICAST)
LOG_D(EMU, "[MULTICAST] multicast link start thread\n");
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file pgm_link.c
* \brief implementation a warpper for openpgm for reliable multicast transmission
* \author Navid Nikaein and S. Roux
* \date 2013 - 2014
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
#include <pthread.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#if defined(ENABLE_PGM_TRANSPORT)
#include <pgm/pgm.h>
#include "assertions.h"
#include "pgm_link.h"
#include "multicast_link.h"
#include "UTIL/OCG/OCG.h"
#include "UTIL/OCG/OCG_extern.h"
#include "UTIL/LOG/log.h"
// #define ENABLE_PGM_DEBUG
typedef struct {
pgm_sock_t *sock;
uint16_t port;
uint8_t rx_buffer[40000];
} pgm_multicast_group_t;
pgm_multicast_group_t pgm_multicast_group[MULTICAST_LINK_NUM_GROUPS];
static
int pgm_create_socket(int index, const char *if_addr);
unsigned int pgm_would_block = 1;
#if defined(ENABLE_PGM_DEBUG)
static void
log_handler (
const int log_level,
const char* message,
void* closure
)
{
printf("%s\n", message);
}
#endif
int pgm_oai_init(char *if_addr)
{
pgm_error_t* pgm_err = NULL;
memset(pgm_multicast_group, 0,
MULTICAST_LINK_NUM_GROUPS * sizeof(pgm_multicast_group_t));
#if defined(ENABLE_PGM_DEBUG)
pgm_messages_init();
pgm_min_log_level = PGM_LOG_LEVEL_DEBUG;
pgm_log_mask = 0xFFF;
pgm_log_set_handler(log_handler, NULL);
#endif
if (!pgm_init(&pgm_err)) {
LOG_E(EMU, "Unable to start PGM engine: %s\n", pgm_err->message);
pgm_error_free (pgm_err);
exit(EXIT_FAILURE);
}
return pgm_create_socket(oai_emulation.info.multicast_group, if_addr);
}
int pgm_recv_msg(int group, uint8_t *buffer, uint32_t length,
unsigned int frame, unsigned int next_slot)
{
size_t num_bytes = 0;
int status = 0;
pgm_error_t* pgm_err = NULL;
struct pgm_sockaddr_t from;
socklen_t fromlen = sizeof(from);
uint32_t timeout = 0;
int flags = 0;
if (pgm_would_block == 0) {
flags = MSG_DONTWAIT;
}
DevCheck((group <= MULTICAST_LINK_NUM_GROUPS) && (group >= 0),
group, MULTICAST_LINK_NUM_GROUPS, 0);
#ifdef DEBUG_EMU
LOG_I(EMU, "[PGM] Entering recv function for group %d\n", group);
#endif
do {
status = pgm_recvfrom(pgm_multicast_group[group].sock,
buffer,
length,
flags,
&num_bytes,
&from,
&fromlen,
&pgm_err);
if (PGM_IO_STATUS_NORMAL == status) {
#ifdef DEBUG_EMU
LOG_D(EMU, "[PGM] Received %d bytes for group %d\n", num_bytes, group);
#endif
return num_bytes;
} else if (PGM_IO_STATUS_TIMER_PENDING == status) {
if (pgm_would_block == 0) {
/* We sleep for 50 usec */
usleep(50);
timeout ++;
if (timeout == (1000000 / 50)) {
LOG_W(EMU, "[PGM] A packet has been lost -> ask for retransmit\n");
/* If we do not receive a packet after 10000usec
* -> send a NACK */
bypass_tx_nack(frame, next_slot);
timeout = 0;
}
}
} else if (PGM_IO_STATUS_RESET == status) {
LOG_W(EMU, "[PGM] Got session reset\n");
} else {
#ifdef DEBUG_EMU
LOG_D(EMU, "[PGM] Got status %d\n", status);
#endif
if (pgm_err) {
LOG_E(EMU, "[PGM] recvform failed: %s", pgm_err->message);
pgm_error_free (pgm_err);
pgm_err = NULL;
}
}
} while(status != PGM_IO_STATUS_NORMAL);
return -1;
}
int pgm_link_send_msg(int group, uint8_t *data, uint32_t len)
{
int status;
size_t bytes_written = 0;
do {
status = pgm_send(pgm_multicast_group[group].sock, data, len, &bytes_written);
} while(status == PGM_IO_STATUS_WOULD_BLOCK);
if (status != PGM_IO_STATUS_NORMAL) {
return -1;
}
return bytes_written;
}
static
int pgm_create_socket(int index, const char *if_addr)
{
struct pgm_addrinfo_t* res = NULL;
pgm_error_t* pgm_err = NULL;
sa_family_t sa_family = AF_INET;
int udp_encap_port = 46014 + index;
int max_tpdu = 1500;
int sqns = 100;
int port = 0;
struct pgm_sockaddr_t addr;
int blocking = 1;
int multicast_loop = 0;
int multicast_hops = 0;
int dscp, i;
port = udp_encap_port;
/* Use PGM */
udp_encap_port = 0;
LOG_D(EMU, "[PGM] Preparing socket for group %d and address %s\n",
index, if_addr);
if (!pgm_getaddrinfo(if_addr, NULL, &res, &pgm_err)) {
LOG_E(EMU, "Parsing network parameter: %s\n", pgm_err->message);
goto err_abort;
}
if (udp_encap_port) {
LOG_I(EMU, "[PGM] Creating PGM/UDP socket for encapsulated port %d\n",
udp_encap_port);
if (!pgm_socket (&pgm_multicast_group[index].sock, sa_family,
SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) {
LOG_E(EMU, "[PGM] Socket: %s\n", pgm_err->message);
goto err_abort;
}
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port,
sizeof(udp_encap_port));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port,
sizeof(udp_encap_port));
} else {
LOG_I(EMU, "[PGM] Creating PGM/IP socket\n");
if (!pgm_socket(&pgm_multicast_group[index].sock, sa_family,
SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) {
LOG_E(EMU, "Creating PGM/IP socket: %s\n", pgm_err->message);
goto err_abort;
}
}
{
/* Use RFC 2113 tagging for PGM Router Assist */
const int no_router_assist = 0;
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_IP_ROUTER_ALERT, &no_router_assist,
sizeof(no_router_assist));
}
// pgm_drop_superuser();
{
/* set PGM parameters */
const int recv_only = 0,
passive = 0,
peer_expiry = pgm_secs (300),
spmr_expiry = pgm_msecs (250),
nak_bo_ivl = pgm_msecs (10),
nak_rpt_ivl = pgm_secs (2),
nak_rdata_ivl = pgm_secs (2),
nak_data_retries = 50,
nak_ncf_retries = 50,
ambient_spm = pgm_secs(30);
const int heartbeat_spm[] = {
pgm_msecs (100),
pgm_msecs (100),
pgm_msecs (100),
pgm_msecs (100),
pgm_msecs (1300),
pgm_secs (7),
pgm_secs (16),
pgm_secs (25),
pgm_secs (30)
};
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_RECV_ONLY, &recv_only, sizeof(recv_only));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_PASSIVE, &passive, sizeof(passive));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_MTU, &max_tpdu, sizeof(max_tpdu));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_RXW_SQNS, &sqns, sizeof(sqns));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_TXW_SQNS, &sqns, sizeof(sqns));
}
/* create global session identifier */
memset (&addr, 0, sizeof(addr));
/* sa_port should be in host byte order */
addr.sa_port = port;
addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT + index;
if (!pgm_gsi_create_from_hostname(&addr.sa_addr.gsi, &pgm_err)) {
LOG_E(EMU, "[PGM] Creating GSI: %s\n", pgm_err->message);
goto err_abort;
}
LOG_D(EMU, "[PGM] Created GSI %s\n", pgm_tsi_print(&addr.sa_addr));
/* assign socket to specified address */
{
struct pgm_interface_req_t if_req;
memset (&if_req, 0, sizeof(if_req));
if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;
if_req.ir_scope_id = 0;
if (AF_INET6 == sa_family) {
struct sockaddr_in6 sa6;
memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6));
if_req.ir_scope_id = sa6.sin6_scope_id;
}
if (!pgm_bind3(pgm_multicast_group[index].sock, &addr, sizeof(addr),
&if_req, sizeof(if_req), /* tx interface */
&if_req, sizeof(if_req), /* rx interface */
&pgm_err)) {
LOG_E(EMU, "[PGM] Error: %s\n", pgm_err->message);
goto err_abort;
}
}
/* join IP multicast groups */
{
struct group_req req;
struct sockaddr_in addr_in;
memset(&req, 0, sizeof(req));
/* Interface index */
req.gr_interface = res->ai_recv_addrs[0].gsr_interface;
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(port);
for (i = 0; i < MULTICAST_LINK_NUM_GROUPS; i++) {
addr_in.sin_addr.s_addr = inet_addr(multicast_group_list[i]);
memcpy(&req.gr_group, &addr_in, sizeof(addr_in));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_JOIN_GROUP, &req,
sizeof(struct group_req));
}
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_SEND_GROUP, &req,
sizeof(struct group_req));
}
pgm_freeaddrinfo(res);
res = NULL;
/* set IP parameters */
multicast_hops = 64;
dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM,
PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));
if (AF_INET6 != sa_family)
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, PGM_TOS,
&dscp, sizeof(dscp));
pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, PGM_NOBLOCK,
&blocking, sizeof(blocking));
if (!pgm_connect(pgm_multicast_group[index].sock, &pgm_err)) {
LOG_E(EMU, "[PGM] Connecting socket: %s\n", pgm_err->message);
goto err_abort;
}
return 0;
err_abort:
if (NULL != pgm_multicast_group[index].sock) {
pgm_close(pgm_multicast_group[index].sock, FALSE);
pgm_multicast_group[index].sock = NULL;
}
if (NULL != res) {
pgm_freeaddrinfo(res);
res = NULL;
}
if (NULL != pgm_err) {
pgm_error_free(pgm_err);
pgm_err = NULL;
}
exit(EXIT_FAILURE);
}
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef PGM_LINK_H_
#define PGM_LINK_H_
/* Define prototypes only if enabled */
#if defined(ENABLE_PGM_TRANSPORT)
void bypass_tx_nack(unsigned int frame, unsigned int next_slot);
int pgm_oai_init(char *if_name);
int pgm_recv_msg(int group, uint8_t *buffer, uint32_t length,
unsigned int frame, unsigned int next_slot);
int pgm_link_send_msg(int group, uint8_t *data, uint32_t len);
#endif
#endif /* PGM_LINK_H_ */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \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
void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) {
int i;
int error_code_UE, error_code_proc_UE;
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;
//struct timespec time_req_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_start_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_addr,
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 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;
/* TODO: check if setting time0 has to be done here */
clock_gettime(CLOCK_MONOTONIC,&time0);
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 : %llu\tMax RX time : %llu\tMin RX time : %llu\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;
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,
&timestamp_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: %"PRId64" idx=%"PRId64"\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);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file eNB_transport_IQ.c
* \brief eNB transport IQ samples
* \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 PRINTF_PERIOD 3750
#define HEADER_SIZE ((sizeof(int32_t) + sizeof(openair0_timestamp))>>2)
pthread_cond_t sync_eNB_cond[4];
pthread_mutex_t sync_eNB_mutex[4];
pthread_mutex_t sync_trx_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t sync_trx_cond=PTHREAD_COND_INITIALIZER;
openair0_timestamp nrt_eNB_counter[4]= {0,0,0,0};
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;
void *rrh_eNB_thread_status;
int sync_eNB_rx[4]= {-1,-1,-1,-1};
unsigned int sync_trx=0;
int32_t **tx_buffer_eNB;
int32_t **rx_buffer_eNB;
void **rx_eNB; //was fixed to 2 ant
void **tx_eNB; //was fixed to 2 ant
openair0_timestamp timestamp_eNB_tx[4]= {0,0,0,0};// all antennas must have the same ts
openair0_timestamp timestamp_eNB_rx[4]= {0,0,0,0};
openair0_timestamp timestamp_rx=0,timestamp_tx=0;
unsigned int rx_pos=0, next_rx_pos=0;
unsigned int tx_pos=0, tx_pos_rf=0, prev_tx_pos=0;
unsigned int rt_period=0;
struct itimerspec timerspec;
pthread_mutex_t timer_mutex;
/*! \fn void *rrh_eNB_rx_thread(void *arg)
* \brief this function
* \param[in]
* \return none
* \note
* @ingroup _oai
*/
void *rrh_eNB_rx_thread(void *);
/*! \fn void *rrh_eNB_tx_thread(void *arg)
* \brief this function
* \param[in]
* \return none
* \note
* @ingroup _oai
*/
void *rrh_eNB_tx_thread(void *);
/*! \fn void *rrh_eNB_thread(void *arg)
* \brief this function
* \param[in]
* \return none
* \note
* @ingroup _oai
*/
void *rrh_eNB_thread(void *);
/*! \fn void check_dev_config( rrh_module_t *mod_enb)
* \brief this function
* \param[in] *mod_enb
* \return none
* \note
* @ingroup _oai
*/
static void check_dev_config( rrh_module_t *mod_enb);
/*! \fn void calc_rt_period_ns( openair0_config_t openair0_cfg)
* \brief this function
* \param[in] openair0_cfg
* \return none
* \note
* @ingroup _oai
*/
static void calc_rt_period_ns( openair0_config_t *openair0_cfg);
void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag) {
int error_code_eNB;
pthread_t main_rrh_eNB_thread;
pthread_attr_t attr;
struct sched_param sched_param_rrh;
RT_flag_eNB=RT_flag;
NRT_flag_eNB=NRT_flag;
/* init socket and have handshake-like msg with client to exchange parameters */
mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port make it plus_id
mod_enb->devs->openair0_cfg = mod_enb->eth_dev.openair0_cfg;
/* check sanity of configuration parameters and print */
check_dev_config(mod_enb);
if (rf_config_file[0] == '\0')
mod_enb->devs->openair0_cfg->configFilename = NULL;
else
mod_enb->devs->openair0_cfg->configFilename = rf_config_file;
/* initialize and configure the RF device */
if (openair0_device_load(mod_enb->devs, mod_enb->devs->openair0_cfg)<0) {
LOG_E(RRH,"Exiting, cannot initialize RF device.\n");
exit(-1);
} else {
if (mod_enb->devs->type != NONE_DEV) {
/* start RF device */
if (mod_enb->devs->type == EXMIMO_DEV) {
//call start function for exmino
} else {
if (mod_enb->devs->trx_start_func(mod_enb->devs)!=0)
LOG_E(RRH,"Unable to initiate RF device.\n");
else
LOG_I(RRH,"RF device has been initiated.\n");
}
}
}
/* create main eNB module thread
main_rrh_eNB_thread allocates memory
for TX/RX buffers and creates TX/RX
threads for every eNB module */
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);
error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)mod_enb);
if (error_code_eNB) {
LOG_E(RRH,"Error while creating eNB thread\n");
exit(-1);
}
}
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;
int32_t i,j;
void *tmp;
unsigned int samples_per_frame=0;
samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
while (rrh_exit==0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX, 1 );
/* calculate packet period */
calc_rt_period_ns(dev->eth_dev.openair0_cfg);
/* 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 (size of samples is 4 bytes) */
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_buffer_eNB address =%p tx_buffer_eNB address =%p \n",rx_buffer_eNB,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 *)malloc16(sizeof(int32_t)*(samples_per_frame + 32));
memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32));
rx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) );
LOG_D(RRH,"i=%d rx_buffer_eNB[i]=%p tmp= %p\n",i,rx_buffer_eNB[i],tmp);
}
/* tx_buffer_eNB points to the beginning of data */
for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
tmp=(void *)malloc16(sizeof(int32_t)*(samples_per_frame + 32));
memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32));
tx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) );
LOG_D(RRH,"i= %d tx_buffer_eNB[i]=%p tmp= %p \n",i,tx_buffer_eNB[i],tmp);
}
/* dummy initialization for TX/RX buffers */
for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
for (j=0; j<samples_per_frame; j++) {
rx_buffer_eNB[i][j]=32+i;
}
}
/* 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++) {
tx_buffer_eNB[i][j]=12+i;
}
}
/* allocate TX/RX buffers pointers used in write/read operations */
rx_eNB = (void**)malloc16(dev->eth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*));
tx_eNB = (void**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*));
/* init mutexes */
for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
pthread_mutex_init(&sync_eNB_mutex[i],NULL);
pthread_cond_init(&sync_eNB_cond[i],NULL);
}
/* init mutexes */
pthread_mutex_init(&sync_trx_mutex,NULL);
/* create eNB module's TX/RX threads */
#ifdef DEADLINE_SCHEDULER
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_I(RRH,"[eNB][SCHED] deadline scheduling applied to eNB 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_I(RRH,"[eNB][SCHED] FIFO scheduling applied to eNB 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);
}
/* create timer thread; when no RF device is present a software clock is generated */
if (dev->devs->type == NONE_DEV) {
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;
#ifdef DEADLINE_SCHEDULER
error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec);
LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to timer thread \n");
#else
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);
pthread_mutex_init(&timer_mutex,NULL);
error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec);
LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to timer thread \n");
#endif
if (error_code_timer) {
LOG_E(RRH,"Error while creating timer proc thread\n");
exit(-1);
}
}
while (rrh_exit==0)
sleep(1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,0 );
}
rrh_eNB_thread_status = 0;
pthread_exit(&rrh_eNB_thread_status);
return(0);
}
/* Receive from RF and transmit to RRH */
void *rrh_eNB_rx_thread(void *arg) {
/* measurement 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=0 ,pck_rx=0, s_cnt=0;
openair0_timestamp last_hw_counter=0; //volatile int64_t
unsigned int samples_per_frame=0,samples_per_subframe=0, spp_rf=0, spp_eth=0;
uint8_t loopback=0,measurements=0;
unsigned int subframe=0;
unsigned int frame=0;
time_req_1us.tv_sec = 0;
time_req_1us.tv_nsec =1000; //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue
spp_eth = dev->eth_dev.openair0_cfg->samples_per_packet;
spp_rf = dev->devs->openair0_cfg->samples_per_packet;
samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
samples_per_subframe = (unsigned int)samples_per_frame/10;
loopback = dev->loopback;
measurements = dev->measurements;
next_rx_pos = spp_eth;
#ifdef DEADLINE_SCHEDULER
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.8 * 100) * 10000;//4 * 10000;
attr.sched_deadline = (0.9 * 100) * 10000;//rt_period-2000;
attr.sched_period = 1 * 1000000;//rt_period;
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) {
while (rx_pos <(1 + subframe)*samples_per_subframe) {
//LOG_D(RRH,"starting a new send:%d %d\n",sync_trx,frame);
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_HW_FRAME_RX, frame);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME_RX, subframe );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK, pck_rx );
LOG_D(RRH,"pack=%d rx_pos=%d subframe=%d frame=%d\n ",pck_rx, rx_pos, subframe,frame);
if (dev->devs->type == NONE_DEV) {
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_CNT, s_cnt );
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;//get current 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);
s_cnt++;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 0 );
}
}
}
}
}
if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1);
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);
}
}
for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
LOG_D(RRH," rx_eNB[i]=%p rx_buffer_eNB[i][rx_pos]=%p ,rx_pos=%d, i=%d ts=%d\n",rx_eNB[i],&rx_buffer_eNB[i][rx_pos],rx_pos,i,timestamp_rx);
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
if (dev->devs->type != NONE_DEV) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 1 );
/* Read operation to RF device (RX)*/
if ( dev->devs->trx_read_func (dev->devs,
&timestamp_rx,
rx_eNB,
spp_rf,
dev->devs->openair0_cfg->rx_num_channels
)<0) {
perror("RRH eNB : USRP read");
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 0 );
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_TS, timestamp_rx&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
if ((bytes_sent = dev->eth_dev.trx_write_func (&dev->eth_dev,
timestamp_rx,
rx_eNB,
spp_eth,
dev->eth_dev.openair0_cfg->rx_num_channels,
0))<0) {
perror("RRH eNB : ETHERNET write");
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
/* when there is no RF timestamp is updated by number of samples */
if (dev->devs->type == NONE_DEV) {
timestamp_rx+=spp_eth;
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_I(RRH,"Max value %d update at rx_position %d \n",total_rx_time,timestamp_rx);
}
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 ns\tMax RX time : %lu ns\tMin RXX time : %lu ns\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]);
}
rx_pos += spp_eth;
pck_rx++;
next_rx_pos=(rx_pos+spp_eth);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 0 );
/*
if (frame>50) {
pthread_mutex_lock(&sync_trx_mutex);
while (sync_trx) {
pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex);
}
sync_trx=1;
LOG_D(RRH,"out of while send:%d %d\n",sync_trx,frame);
pthread_cond_signal(&sync_trx_cond);
pthread_mutex_unlock(&sync_trx_mutex);
}*/
} // while
subframe++;
s_cnt=0;
/* wrap around rx buffer index */
if (next_rx_pos >= samples_per_frame)
next_rx_pos -= samples_per_frame;
if (rx_pos >= samples_per_frame)
rx_pos -= samples_per_frame;
/* wrap around subframe number */
if (subframe == 10 ) {
subframe = 0;
frame++;
}
} //while (eNB_exit==0)
return 0;
}
/* Receive from eNB and transmit to RF */
void *rrh_eNB_tx_thread(void *arg) {
struct timespec time0,time1,time2;
rrh_module_t *dev = (rrh_module_t *)arg;
struct timespec time_req_1us, time_rem_1us;
ssize_t bytes_received;
int i;
//openair0_timestamp last_hw_counter=0;
unsigned int samples_per_frame=0,samples_per_subframe=0;
unsigned int spp_rf=0, spp_eth=0;
uint8_t loopback=0,measurements=0;
unsigned int subframe=0,frame=0;
unsigned int pck_tx=0;
#ifdef DEADLINE_SCHEDULER
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.8 * 100) * 10000;
attr.sched_deadline = (0.9 * 100) * 10000;
attr.sched_period = 1 * 1000000;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB TX thread: sched_setattr failed\n");
exit(-1);
}
#endif
time_req_1us.tv_sec = 1;
time_req_1us.tv_nsec = 0;
spp_eth = dev->eth_dev.openair0_cfg->samples_per_packet;
spp_rf = dev->devs->openair0_cfg->samples_per_packet;
samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
samples_per_subframe = (unsigned int)samples_per_frame/10;
tx_pos=0;
loopback = dev->loopback;
measurements = dev->measurements;
while (rrh_exit == 0) {
while (tx_pos < (1 + subframe)*samples_per_subframe) {
//LOG_D(RRH,"bef lock read:%d %d\n",sync_trx,frame);
//pthread_mutex_lock(&sync_trx_mutex);
//while (!sync_trx) {
//LOG_D(RRH,"in sync read:%d %d\n",sync_trx,frame);
//pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex);
//}
//LOG_D(RRH,"out of while read:%d %d\n",sync_trx,frame);
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_HW_FRAME, frame);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, subframe );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK, pck_tx );
if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1);
for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) 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 );
/* Read operation to ETHERNET device */
if (( bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev,
&timestamp_tx,
tx_eNB,
spp_eth,
dev->eth_dev.openair0_cfg->tx_num_channels))<0) {
perror("RRH eNB : ETHERNET read");
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
if (dev->devs->type != NONE_DEV) {
LOG_D(RRH," tx_buffer_eNB[i][tx_pos]=%x t_buffer_eNB[i][tx_pos+1]=%x t_buffer_eNB[i][tx_pos+2]=%x \n",tx_buffer_eNB[0][tx_pos],tx_buffer_eNB[0][tx_pos+1],tx_buffer_eNB[0][tx_pos+2]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 1 );
/* Write operation to RF device (TX)*/
if ( dev->devs->trx_write_func (dev->devs,
timestamp_tx,
tx_eNB,
spp_rf,
dev->devs->openair0_cfg->tx_num_channels,
1)<0){
perror("RRH eNB : USRP write");
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 0 );
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_tx&0xffffffff );
//if (dev->devs->type == NONE_DEV) 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));
}
prev_tx_pos=tx_pos;
tx_pos += spp_eth;
pck_tx++;
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 0 );
//sync_trx=0;
//pthread_cond_signal(&sync_trx_cond);
//pthread_mutex_unlock(&sync_trx_mutex);
}
/* wrap around tx buffer index */
if (tx_pos >= samples_per_frame)
tx_pos -= samples_per_frame;
/* wrap around subframe number */
subframe++;
if (subframe == 10 ) {
subframe = 0; // the radio frame is complete, start over
frame++;
}
} //while (eNB_exit==0)
return 0;
}
static void calc_rt_period_ns( openair0_config_t *openair0_cfg) {
rt_period= (double)(openair0_cfg->samples_per_packet/(openair0_cfg->samples_per_frame/10.0)*1000000);
AssertFatal(rt_period > 0, "Invalid rt period !%u\n", rt_period);
LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period);
}
static void check_dev_config( rrh_module_t *mod_enb) {
AssertFatal( (mod_enb->devs->openair0_cfg->num_rb_dl==100 || mod_enb->devs->openair0_cfg->num_rb_dl==50 || mod_enb->devs->openair0_cfg->num_rb_dl==25 || mod_enb->devs->openair0_cfg->num_rb_dl==6) , "Invalid number of resource blocks! %d\n", mod_enb->devs->openair0_cfg->num_rb_dl);
AssertFatal( mod_enb->devs->openair0_cfg->samples_per_frame > 0 , "Invalid number of samples per frame! %d\n",mod_enb->devs->openair0_cfg->samples_per_frame);
AssertFatal( mod_enb->devs->openair0_cfg->sample_rate > 0.0, "Invalid sample rate! %f\n", mod_enb->devs->openair0_cfg->sample_rate);
AssertFatal( mod_enb->devs->openair0_cfg->samples_per_packet > 0 , "Invalid number of samples per packet! %d\n",mod_enb->devs->openair0_cfg->samples_per_packet);
AssertFatal( mod_enb->devs->openair0_cfg->rx_num_channels > 0 , "Invalid number of RX antennas! %d\n", mod_enb->devs->openair0_cfg->rx_num_channels);
AssertFatal( mod_enb->devs->openair0_cfg->tx_num_channels > 0 , "Invalid number of TX antennas! %d\n", mod_enb->devs->openair0_cfg->tx_num_channels);
AssertFatal( mod_enb->devs->openair0_cfg->rx_freq[0] > 0.0 ,"Invalid RX frequency! %f\n", mod_enb->devs->openair0_cfg->rx_freq[0]);
AssertFatal( mod_enb->devs->openair0_cfg->tx_freq[0] > 0.0 ,"Invalid TX frequency! %f\n", mod_enb->devs->openair0_cfg->tx_freq[0]);
AssertFatal( mod_enb->devs->openair0_cfg->rx_gain[0] > 0.0 ,"Invalid RX gain! %f\n", mod_enb->devs->openair0_cfg->rx_gain[0]);
AssertFatal( mod_enb->devs->openair0_cfg->tx_gain[0] > 0.0 ,"Invalid TX gain! %f\n", mod_enb->devs->openair0_cfg->tx_gain[0]);
AssertFatal( mod_enb->devs->openair0_cfg->rx_bw > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->rx_bw);
AssertFatal( mod_enb->devs->openair0_cfg->tx_bw > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->tx_bw);
AssertFatal( mod_enb->devs->openair0_cfg->autocal[0] > 0 , "Invalid auto calibration choice! %d\n", mod_enb->devs->openair0_cfg->autocal[0]);
printf("\n---------------------RF device configuration parameters---------------------\n");
printf("\tMod_id=%d\n \tlog level=%d\n \tDL_RB=%d\n \tsamples_per_frame=%d\n \tsample_rate=%f\n \tsamples_per_packet=%d\n \ttx_sample_advance=%d\n \trx_num_channels=%d\n \ttx_num_channels=%d\n \trx_freq_0=%f\n \ttx_freq_0=%f\n \trx_freq_1=%f\n \ttx_freq_1=%f\n \trx_freq_2=%f\n \ttx_freq_2=%f\n \trx_freq_3=%f\n \ttx_freq_3=%f\n \trxg_mode=%d\n \trx_gain_0=%f\n \ttx_gain_0=%f\n \trx_gain_1=%f\n \ttx_gain_1=%f\n \trx_gain_2=%f\n \ttx_gain_2=%f\n \trx_gain_3=%f\n \ttx_gain_3=%f\n \trx_gain_offset_2=%f\n \ttx_gain_offset_3=%f\n \trx_bw=%f\n \ttx_bw=%f\n \tautocal=%d\n",
mod_enb->devs->openair0_cfg->Mod_id,
mod_enb->devs->openair0_cfg->log_level,
mod_enb->devs->openair0_cfg->num_rb_dl,
mod_enb->devs->openair0_cfg->samples_per_frame,
mod_enb->devs->openair0_cfg->sample_rate,
mod_enb->devs->openair0_cfg->samples_per_packet,
mod_enb->devs->openair0_cfg->tx_sample_advance,
mod_enb->devs->openair0_cfg->rx_num_channels,
mod_enb->devs->openair0_cfg->tx_num_channels,
mod_enb->devs->openair0_cfg->rx_freq[0],
mod_enb->devs->openair0_cfg->tx_freq[0],
mod_enb->devs->openair0_cfg->rx_freq[1],
mod_enb->devs->openair0_cfg->tx_freq[1],
mod_enb->devs->openair0_cfg->rx_freq[2],
mod_enb->devs->openair0_cfg->tx_freq[2],
mod_enb->devs->openair0_cfg->rx_freq[3],
mod_enb->devs->openair0_cfg->tx_freq[3],
mod_enb->devs->openair0_cfg->rxg_mode[0],
mod_enb->devs->openair0_cfg->tx_gain[0],
mod_enb->devs->openair0_cfg->tx_gain[0],
mod_enb->devs->openair0_cfg->rx_gain[1],
mod_enb->devs->openair0_cfg->tx_gain[1],
mod_enb->devs->openair0_cfg->rx_gain[2],
mod_enb->devs->openair0_cfg->tx_gain[2],
mod_enb->devs->openair0_cfg->rx_gain[3],
mod_enb->devs->openair0_cfg->tx_gain[3],
//mod_enb->devs->openair0_cfg->rx_gain_offset[0],
//mod_enb->devs->openair0_cfg->rx_gain_offset[1],
mod_enb->devs->openair0_cfg->rx_gain_offset[2],
mod_enb->devs->openair0_cfg->rx_gain_offset[3],
mod_enb->devs->openair0_cfg->rx_bw,
mod_enb->devs->openair0_cfg->tx_bw,
mod_enb->devs->openair0_cfg->autocal[0]
);
printf("----------------------------------------------------------------------------\n");
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/** ethernet_lib : API to stream I/Q samples over standard ethernet (RRH component)
*
* Authors: Raymond Knopp <raymond.knopp@eurecom.fr>, Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
*
* Changelog:
* 06.10.2014: Initial version
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <unistd.h>
#include <signal.h>
#include <execinfo.h>
#include <pthread.h>
#include <time.h>
#include "common_lib.h"
#define BUF_LEN 4096+32
#define RRH_eNB_PORT 50000
#define RRH_eNB_DEST_IP "127.0.0.1"
#define RRH_UE_PORT 51000
#define RRH_UE_DEST_IP "127.0.0.1"
#define FRAME_MAX_SIZE 307200//76800
#define DEFAULT_PERIOD_NS 133333//200000
#define START_CMD 1
#define PRINTF_PERIOD 3750
typedef struct {
int eNB_port;
char eNB_dest_ip[20];
int UE_port;
char UE_dest_ip[20];
struct timespec time_req;
} rrh_desc_t;
typedef struct {
int32_t nsamps;
int32_t antenna_index_eNB_rx;
int32_t antenna_index_eNB_tx;
int sockid_eNB;
struct sockaddr clientaddr;
socklen_t clientaddrlen;
} rrh_eNB_desc_t;
typedef struct {
int32_t nsamps;
int32_t antenna_index_UE_rx;
int32_t antenna_index_UE_tx;
int sockid_UE;
struct sockaddr clientaddr;
socklen_t clientaddrlen;
} rrh_UE_desc_t;
int rrh_exit=0;
int32_t tx_buffer_eNB[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE],rx_buffer_eNB[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE];
int32_t tx_buffer_UE[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE],rx_buffer_UE[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE];
void *rrh_eNB_thread_status;
void *rrh_UE_thread_status;
int32_t counter_UE_rx[4]= {0,0,0,0};
int32_t counter_UE_tx[4]= {0,0,0,0};
int32_t counter_eNB_rx[4]= {0,0,0,0};
int32_t counter_eNB_tx[4]= {0,0,0,0};
int32_t overflow_rx_buffer_UE[4]= {0,0,0,0};
int32_t overflow_rx_buffer_eNB[4]= {0,0,0,0};
int32_t nsamps_eNB[4]= {0,0,0,0};
int32_t nsamps_UE[4]= {0,0,0,0};
int32_t UE_tx_started=0,eNB_tx_started=0, UE_rx_started=0,eNB_rx_started=0;
int32_t RT_FLAG=0, NRT_FLAG=1;
openair0_timestamp nrt_eNB_counter[4]= {0,0,0,0};
openair0_timestamp nrt_UE_counter[4]= {0,0,0,0};
openair0_timestamp timestamp_eNB_tx[4],timestamp_eNB_rx[4]= {0,0,0,0};
openair0_timestamp timestamp_UE_tx[4],timestamp_UE_rx[4]= {0,0,0,0};
openair0_timestamp hw_counter=0;
pthread_cond_t sync_UE_cond[4];
pthread_mutex_t sync_UE_mutex[4];
pthread_cond_t sync_eNB_cond[4];
pthread_mutex_t sync_eNB_mutex[4];
pthread_mutex_t timer_mutex;
int sync_UE_rx[4]= {-1,-1,-1,-1};
int sync_eNB_rx[4]= {-1,-1,-1,-1};
//functions prototype
void timer_signal_handler(int);
void *timer_proc(void *);
void *rrh_proc_eNB_thread();
void *rrh_proc_UE_thread();
void *rrh_UE_thread(void *);
void *rrh_UE_rx_thread(void *);
void *rrh_UE_tx_thread(void *);
void *rrh_eNB_thread(void *);
void *rrh_eNB_rx_thread(void *);
void *rrh_eNB_tx_thread(void *);
void timer_signal_handler(int sig)
{
if (sig == SIGALRM) {
pthread_mutex_lock(&timer_mutex);
hw_counter ++;
//printf("[RRH] : hw_counter : %d\n",(int)hw_counter);
pthread_mutex_unlock(&timer_mutex);
}
}
void *timer_proc(void *arg)
{
timer_t timerid; // timer ID for timer
//struct sigevent event; // event to deliver
struct itimerspec *timer = (struct itimerspec*)arg; // the timer data structure
struct itimerspec *old_value;
//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);
while (!rrh_exit) {
sleep(1);
}
timer_delete(timerid);
return (0);
}
void *rrh_proc_eNB_thread()
{
//rrh_desc_t *rrh_desc = (rrh_desc_t *)arg;
int antenna_index,i;
openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0;
struct timespec time_req, time_rem;
int16_t *rxp,*txp;
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_eNB_rx[antenna_index]==0) {
if (!eNB_tx_started) {
eNB_tx_started=1; // set this flag to 1 to indicate that eNB started
if (RT_FLAG==1) {
last_hw_counter=hw_counter;
}
} else {
if (RT_FLAG==1) {
if (hw_counter > last_hw_counter+1) {
printf("L");
// goto end_copy_eNB;
} else {
//printf("hw_counter : %llu, last_hw_counter : %llu\n",hw_counter,last_hw_counter);
while (hw_counter < last_hw_counter+1)
nanosleep(&time_req,&time_rem);
}
}
}
truncated_timestamp = timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE);
truncated_timestamp_final = (timestamp_eNB_tx[antenna_index]+nsamps_eNB[antenna_index])%FRAME_MAX_SIZE;
if ((truncated_timestamp + nsamps_eNB[antenna_index]) > FRAME_MAX_SIZE) {
if ((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE < nsamps_eNB[antenna_index]) && (UE_rx_started==1)) {
overflow_rx_buffer_UE[antenna_index]++;
printf("UE Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_UE[antenna_index],(int)truncated_timestamp);
if (NRT_FLAG==1) {
while ((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE) < nsamps_eNB[antenna_index])
nanosleep(&time_req,&time_rem);
}
}
rxp = (int16_t*)&rx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)];
txp = (int16_t*)&tx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)];
for (i=0; i<(FRAME_MAX_SIZE<<1)-(truncated_timestamp<<1); i++) {
rxp[i] = txp[i]>>6;
}
rxp = (int16_t*)&rx_buffer_UE[antenna_index][(sizeof(openair0_timestamp)>>2)];
txp = (int16_t*)&tx_buffer_eNB[antenna_index][0];
for (i=0; i<nsamps_eNB[antenna_index]-(FRAME_MAX_SIZE)+(truncated_timestamp); i++) {
rxp[i] = txp[i]>>6;
}
/* memcpy(&rx_buffer_UE[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][truncated_timestamp],(FRAME_MAX_SIZE<<2)-(truncated_timestamp<<2));
memcpy(&rx_buffer_UE[antenna_index][(sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][0],(nsamps_eNB[antenna_index]<<2)-(FRAME_MAX_SIZE<<2)+(truncated_timestamp<<2));*/
} else {
if (((truncated_timestamp < (timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE)) && (truncated_timestamp_final > (timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE))) && (UE_rx_started==1)) {
overflow_rx_buffer_UE[antenna_index]++;
printf("UE Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_UE[antenna_index],(int)truncated_timestamp);
if (NRT_FLAG==1) {
while (truncated_timestamp_final > timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE)
nanosleep(&time_req,&time_rem);
}
}
rxp = (int16_t*)&rx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp))];
txp = (int16_t*)&tx_buffer_eNB[antenna_index][truncated_timestamp];
for (i=0; i<(nsamps_eNB[antenna_index]); i++) {
rxp[i] =txp[i]>>6;
}
/*
memcpy(&rx_buffer_UE[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][truncated_timestamp],(nsamps_eNB[antenna_index]<<2));*/
}
// end_copy_eNB :
last_hw_counter=hw_counter;
pthread_mutex_lock(&sync_eNB_mutex[antenna_index]);
sync_eNB_rx[antenna_index]--;
pthread_mutex_unlock(&sync_eNB_mutex[antenna_index]);
}
}
}
return(0);
}
void *rrh_proc_UE_thread()
{
//rrh_desc_t *rrh_desc = (rrh_desc_t *)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;
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==1) {
last_hw_counter=hw_counter;
}
} else {
if (RT_FLAG==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]%(FRAME_MAX_SIZE);
truncated_timestamp_final = (timestamp_UE_tx[antenna_index]+nsamps_UE[antenna_index])%FRAME_MAX_SIZE;
if ((truncated_timestamp + nsamps_UE[antenna_index]) > FRAME_MAX_SIZE) {
if ((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE < 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==1) {
while ((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE) < nsamps_UE[antenna_index])
nanosleep(&time_req,&time_rem);
}
}
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)];
txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)];
for (i=0; i<(FRAME_MAX_SIZE<<1)-(truncated_timestamp<<1); i++) {
rxp[i] = txp[i]>>6;
}
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][(sizeof(openair0_timestamp)>>2)];
txp = (int16_t*)&tx_buffer_UE[antenna_index][0];
for (i=0; i<nsamps_eNB[antenna_index]-(FRAME_MAX_SIZE)+(truncated_timestamp); i++) {
rxp[i] = txp[i]>>6;
}
/*
memcpy(&rx_buffer_eNB[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][truncated_timestamp],(FRAME_MAX_SIZE<<2)-(truncated_timestamp<<2));
memcpy(&rx_buffer_eNB[antenna_index][(sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][0],(nsamps_UE[antenna_index]<<2)-(FRAME_MAX_SIZE<<2)+(truncated_timestamp<<2));*/
} else {
if (((truncated_timestamp < (timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE)) && (truncated_timestamp_final > (timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE))) && (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==1) {
while (truncated_timestamp_final > timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE)
nanosleep(&time_req,&time_rem);
}
}
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_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;
}
/* memcpy(&rx_buffer_eNB[antenna_index][truncated_timestamp+ (sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][truncated_timestamp],(nsamps_UE[antenna_index]<<2));*/
}
//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);
}
void *rrh_UE_rx_thread(void *arg)
{
struct sockaddr clientaddr;
socklen_t clientaddrlen;
rrh_UE_desc_t *rrh_UE_rx_desc = (rrh_UE_desc_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;
int sockid;
char str[INET_ADDRSTRLEN];
unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0;
openair0_timestamp temp, last_hw_counter=0;
antenna_index = rrh_UE_rx_desc->antenna_index_UE_rx;
nsamps = rrh_UE_rx_desc->nsamps;
sockid = rrh_UE_rx_desc->sockid_UE;
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
//printf("Waiting for eNB ...\n");
//printf("[RRH eNB RX thread] received parameters : nsamps : %d, antenna_index : %d\n",nsamps,antenna_index);
clientaddr = rrh_UE_rx_desc->clientaddr;
clientaddrlen = rrh_UE_rx_desc->clientaddrlen;
inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN);
printf("Received UE RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str,
ntohs(((struct sockaddr_in*)&clientaddr)->sin_port));
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==1) {
last_hw_counter=hw_counter;
}
} else {
if (RT_FLAG==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
temp=*(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)];
*(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)]=timestamp_UE_rx[antenna_index];
if ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit
if (((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)) < ((timestamp_UE_rx[antenna_index]+nsamps)%(FRAME_MAX_SIZE))) && (eNB_tx_started==1)) {
printf("UE underflow wraparound timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",(int)(timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)),(int)(timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE));
if (NRT_FLAG==1) {
while ((timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE) < ((timestamp_UE_rx[antenna_index]+nsamps)%(FRAME_MAX_SIZE)))
nanosleep(&time_req_1us,&time_rem_1us);
}
}
if ((bytes_sent = sendto(sockid,
&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)],
((FRAME_MAX_SIZE)<<2) - ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE))<<2) + sizeof(openair0_timestamp),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH UE : sendto for RX");
if ((bytes_sent = sendto(sockid,
&rx_buffer_UE[antenna_index][0],
(nsamps<<2) - ((FRAME_MAX_SIZE)<<2) + ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE))<<2),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH UE : sendto for RX");
} else {
if (((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE)< timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)
&& (((timestamp_UE_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)) && (eNB_tx_started==1) ) {
printf("UE underflow timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",(int)(timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE),(int)(timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE));
if (NRT_FLAG==1) {
while (((timestamp_UE_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)) {
nanosleep(&time_req_1us,&time_rem_1us);
}
}
}
if ((bytes_sent = sendto(sockid,
&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)],
(nsamps<<2)+sizeof(openair0_timestamp),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH UE thread: sendto for RX");
}
//printf("bytes_sent %d(timestamp_UE_rx[%d] %d)\n",(int)bytes_sent,antenna_index,(int)timestamp_UE_rx[antenna_index]);
*(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)]=temp;
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 (rrh_exit==0)
return(0);
}
void *rrh_UE_tx_thread(void *arg)
{
struct sockaddr clientaddr;
socklen_t clientaddrlen;
struct timespec time0a,time0,time1,time2;
rrh_UE_desc_t *rrh_UE_tx_desc = (rrh_UE_desc_t *)arg;
// struct timespec time_rem;
struct timespec time_req_1us, time_rem_1us;
ssize_t bytes_received;
int antenna_index, nsamps;
int8_t buf[BUF_LEN];
int trace_cnt=0;
int sockid;
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
antenna_index = rrh_UE_tx_desc->antenna_index_UE_tx;
nsamps = rrh_UE_tx_desc->nsamps;
sockid = rrh_UE_tx_desc->sockid_UE;
while (rrh_exit == 0) {
clock_gettime(CLOCK_MONOTONIC,&time0a);
bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen);
timestamp_eNB_tx[antenna_index] = *(openair0_timestamp*)(buf+4);
clock_gettime(CLOCK_MONOTONIC,&time1);
if (NRT_FLAG==1) {
nrt_UE_counter[antenna_index]++;
}
//printf("Received UE TX request for antenna %d, nsamps %d, timestamp %d bytes_received %d\n",antenna_index,nsamps,(int)timestamp_UE_tx[antenna_index],(int)bytes_received);
if ((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit
memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),
(FRAME_MAX_SIZE<<2)-((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE))<<2));
memcpy(&tx_buffer_UE[antenna_index][0],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t)+(FRAME_MAX_SIZE*4)-((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE))<<2),
(nsamps<<2)-((FRAME_MAX_SIZE-(timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)))<<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]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),(nsamps<<2));
}
//printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>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)%FRAME_MAX_SIZE;
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);
}
void *rrh_UE_thread(void *arg)
{
int sockid=-1;
struct sockaddr_in serveraddr;
struct sockaddr clientaddr;
socklen_t clientaddrlen;
rrh_desc_t *rrh_desc = (rrh_desc_t *)arg;
char str[INET_ADDRSTRLEN];
//int8_t msg_header[4+sizeof(openair0_timestamp)];
int8_t buf[BUF_LEN];
int16_t cmd; //,nsamps,antenna_index;
ssize_t bytes_received;
// struct timespec time_rem;
// ssize_t bytes_sent;
// openair0_timestamp temp;
// openair0_timestamp last_hw_counter=0;
struct timespec time_req_1us, time_rem_1us;
rrh_UE_desc_t rrh_UE_desc;
pthread_t UE_rx_thread, UE_tx_thread;
pthread_attr_t attr_UE_rx, attr_UE_tx;
struct sched_param sched_param_UE_rx, sched_param_UE_tx;
int error_code_UE_rx, error_code_UE_tx;
time_req_1us.tv_sec = 0;
time_req_1us.tv_nsec = 1000;
while (rrh_exit==0) {
sockid=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (sockid==-1) {
perror("Cannot create UE socket: ");
rrh_exit=1;
}
bzero((char *)&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(rrh_desc->UE_port);
inet_pton(AF_INET,rrh_desc->UE_dest_ip,&serveraddr.sin_addr.s_addr);
inet_ntop(AF_INET, &(serveraddr.sin_addr), str, INET_ADDRSTRLEN);
printf("Binding to UE socket for %s:%d\n",str,ntohs(serveraddr.sin_port));
if (bind(sockid,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0) {
perror("Cannot bind to UE socket: ");
rrh_exit = 1;
}
// now wait for commands from eNB
// get header info
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
//printf("Waiting for UE ...\n");
bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen);
cmd = buf[0];
rrh_UE_desc.antenna_index_UE_rx = cmd>>1;
rrh_UE_desc.antenna_index_UE_tx = cmd>>1;
//rrh_eNB_desc.timestamp_eNB_tx[rrh_eNB_desc.antenna_index_eNB_tx] = *(openair0_timestamp*)(buf+4); //we don't need timestamp when receiving the first command
rrh_UE_desc.nsamps = *(int16_t *)(buf+2);
rrh_UE_desc.sockid_UE = sockid;
rrh_UE_desc.clientaddr = clientaddr;
rrh_UE_desc.clientaddrlen = clientaddrlen;
cmd = cmd&1;
inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN);
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 *)&rrh_UE_desc);
error_code_UE_tx = pthread_create(&UE_tx_thread, &attr_UE_tx, rrh_UE_tx_thread, (void *)&rrh_UE_desc);
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);
}
}
close(sockid);
rrh_UE_thread_status = 0;
pthread_exit(&rrh_UE_thread_status);
return(0);
}
void *rrh_eNB_rx_thread(void *arg)
{
struct sockaddr clientaddr;
socklen_t clientaddrlen;
rrh_eNB_desc_t *rrh_eNB_rx_desc = (rrh_eNB_desc_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;
int sockid;
char str[INET_ADDRSTRLEN];
unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0;
openair0_timestamp temp, last_hw_counter=0;
antenna_index = rrh_eNB_rx_desc->antenna_index_eNB_rx;
nsamps = rrh_eNB_rx_desc->nsamps;
sockid = rrh_eNB_rx_desc->sockid_eNB;
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
//printf("Waiting for eNB ...\n");
//printf("[RRH eNB RX thread] received parameters : nsamps : %d, antenna_index : %d\n",nsamps,antenna_index);
clientaddr = rrh_eNB_rx_desc->clientaddr;
clientaddrlen = rrh_eNB_rx_desc->clientaddrlen;
inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN);
printf("Received eNB RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str,
ntohs(((struct sockaddr_in*)&clientaddr)->sin_port));
while (rrh_exit == 0) {
//printf("Received eNB RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str,
// ntohs(((struct sockaddr_in*)&clientaddr)->sin_port));
if (!eNB_rx_started) {
eNB_rx_started=1; // set this flag to 1 to indicate that eNB started
if (RT_FLAG==1) {
last_hw_counter=hw_counter;
}
} else {
if (RT_FLAG==1) {
if (hw_counter > last_hw_counter+1) {
printf("L");
// goto end_copy_eNB;
} else {
while (hw_counter < last_hw_counter+1)
nanosleep(&time_req_1us,&time_rem_1us);
}
}
}
clock_gettime(CLOCK_MONOTONIC,&time1);
// send return
temp=*(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)];
*(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)]=timestamp_eNB_rx[antenna_index];
if ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit
if ((timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE < ((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE)) && (UE_tx_started==1)) {
printf("eNB underflow\n");
if (NRT_FLAG==1) {
while ((timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE) < nsamps)
nanosleep(&time_req_1us,&time_rem_1us);
}
}
if ((bytes_sent = sendto(sockid,
&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)],
((FRAME_MAX_SIZE)<<2) - ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE))<<2) + sizeof(openair0_timestamp),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH eNB : sendto for RX");
if ((bytes_sent = sendto(sockid,
&rx_buffer_eNB[antenna_index][0],
(nsamps<<2) - ((FRAME_MAX_SIZE)<<2) + ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE))<<2),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH eNB : sendto for RX");
} else {
if (((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE)< timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE)
&& (((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE)) && (UE_tx_started==1)) {
printf("eNB underflow\n");
if (NRT_FLAG==1) {
while (((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE))
nanosleep(&time_req_1us,&time_rem_1us);
}
}
if ((bytes_sent = sendto(sockid,
&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)],
(nsamps<<2)+sizeof(openair0_timestamp),
0,
(struct sockaddr*)&clientaddr,
sizeof(struct sockaddr)))<0)
perror("RRH eNB : sendto for RX");
}
//printf("bytes_sent %d(timestamp_eNB_rx[%d] %d)\n",(int)bytes_sent,antenna_index,(int)timestamp_eNB_rx[antenna_index]);
*(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)]=temp;
timestamp_eNB_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 eNB 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 (rrh_exit==0)
return(0);
}
void *rrh_eNB_tx_thread(void *arg)
{
struct sockaddr clientaddr;
socklen_t clientaddrlen;
struct timespec time0a,time0,time1,time2;
rrh_eNB_desc_t *rrh_eNB_tx_desc = (rrh_eNB_desc_t *)arg;
// struct timespec time_rem;
struct timespec time_req_1us, time_rem_1us;
ssize_t bytes_received;
int antenna_index, nsamps;
int8_t buf[BUF_LEN];
int trace_cnt=0;
int sockid;
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
//printf("Waiting for eNB ...\n");
antenna_index = rrh_eNB_tx_desc->antenna_index_eNB_tx;
nsamps = rrh_eNB_tx_desc->nsamps;
sockid = rrh_eNB_tx_desc->sockid_eNB;
while (rrh_exit == 0) {
clock_gettime(CLOCK_MONOTONIC,&time0a);
bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen);
timestamp_eNB_tx[antenna_index] = *(openair0_timestamp*)(buf+4);
clock_gettime(CLOCK_MONOTONIC,&time1);
if (NRT_FLAG==1) {
nrt_eNB_counter[antenna_index]++;
}
//printf("Received eNB TX request for antenna %d, nsamps %d, timestamp %d bytes_received %d\n",antenna_index,nsamps,(int)timestamp_eNB_tx[antenna_index],(int)bytes_received);
if ((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit
memcpy(&tx_buffer_eNB[antenna_index][timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),
((FRAME_MAX_SIZE)<<2)-((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2));
//printf("Done first part size : %d\n",(int32_t)(((FRAME_MAX_SIZE)<<2)-((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2)));
memcpy(&tx_buffer_eNB[antenna_index][0],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t) + ((FRAME_MAX_SIZE)<<2) -((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2),
(nsamps<<2)-((FRAME_MAX_SIZE)<<2)+((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2));
//printf("Received eNB TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2));
} else {
memcpy(&tx_buffer_eNB[antenna_index][timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),nsamps<<2);
}
while (sync_eNB_rx[antenna_index]==0)
nanosleep(&time_req_1us,&time_rem_1us);
//printf("launching eNB proc\n");
pthread_mutex_lock(&sync_eNB_mutex[antenna_index]);
sync_eNB_rx[antenna_index]++;
if (!sync_eNB_rx[antenna_index]) {
counter_eNB_tx[antenna_index]=(counter_eNB_tx[antenna_index]+nsamps)%FRAME_MAX_SIZE;
nsamps_eNB[antenna_index]=nsamps;
} else {
printf("rrh_eNB_proc thread is busy, will exit\n");
exit(-1);
}
pthread_mutex_unlock(&sync_eNB_mutex[antenna_index]);
clock_gettime(CLOCK_MONOTONIC,&time2);
//if (trace_cnt++ < 10)
// printf("TX: t0 %llu (time from previous run) t1 %llu (time of memcpy TX samples), t2 %llu (total time)\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec),
// (long long unsigned int)(time2.tv_nsec - time1.tv_nsec),
// (long long unsigned int)(time2.tv_nsec - time0.tv_nsec));
memcpy(&time0,&time2,sizeof(struct timespec));
}
return(0);
}
void *rrh_eNB_thread(void *arg)
{
int sockid=-1;
struct sockaddr_in serveraddr;
struct sockaddr clientaddr;
socklen_t clientaddrlen;
rrh_desc_t *rrh_desc = (rrh_desc_t *)arg;
char str[INET_ADDRSTRLEN];
//int8_t msg_header[4+sizeof(openair0_timestamp)];
int8_t buf[BUF_LEN];
int16_t cmd; //,nsamps,antenna_index;
ssize_t bytes_received;
//ssize_t bytes_sent;
//openair0_timestamp temp, last_hw_counter=0;
//struct timespec time_rem;
struct timespec time_req_1us, time_rem_1us;
//struct timespec time0a,time0,time1,time2;
//int trace_cnt=0;
rrh_eNB_desc_t rrh_eNB_desc;
pthread_t eNB_rx_thread, eNB_tx_thread;
pthread_attr_t attr_eNB_rx, attr_eNB_tx;
struct sched_param sched_param_eNB_rx, sched_param_eNB_tx;
int error_code_eNB_rx, error_code_eNB_tx;
time_req_1us.tv_sec = 0;
time_req_1us.tv_nsec = 1000;
while (rrh_exit==0) {
sockid=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (sockid==-1) {
perror("Cannot create eNB socket: ");
rrh_exit=1;
}
bzero((char *)&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(rrh_desc->eNB_port);
inet_pton(AF_INET,rrh_desc->eNB_dest_ip,&serveraddr.sin_addr.s_addr);
inet_ntop(AF_INET, &(serveraddr.sin_addr), str, INET_ADDRSTRLEN);
printf("Binding to eNB socket for %s:%d\n",str,ntohs(serveraddr.sin_port));
if (bind(sockid,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0) {
perror("Cannot bind to eNB socket: ");
rrh_exit = 1;
}
// now wait for commands from eNB
// get header info
bzero((void*)&clientaddr,sizeof(struct sockaddr));
clientaddrlen = sizeof(struct sockaddr);
//printf("Waiting for eNB ...\n");
bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen);
cmd = buf[0];
rrh_eNB_desc.antenna_index_eNB_rx = cmd>>1;
rrh_eNB_desc.antenna_index_eNB_tx = cmd>>1;
//rrh_eNB_desc.timestamp_eNB_tx[rrh_eNB_desc.antenna_index_eNB_tx] = *(openair0_timestamp*)(buf+4); //we don't need timestamp when receiving the first command
rrh_eNB_desc.nsamps = *(int16_t *)(buf+2);
rrh_eNB_desc.sockid_eNB = sockid;
rrh_eNB_desc.clientaddr = clientaddr;
rrh_eNB_desc.clientaddrlen = clientaddrlen;
//cmd = cmd&1;
cmd = cmd|1;//in order to make cmd evalution dummy (the first message from lte to rrh has changed, see: @ethernet_lib.c trx_start_func has been substituted by trx_request_func )
inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN);
if (cmd==START_CMD) {
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 *)&rrh_eNB_desc);
error_code_eNB_tx = pthread_create(&eNB_tx_thread, &attr_eNB_tx, rrh_eNB_tx_thread, (void *)&rrh_eNB_desc);
if (error_code_eNB_rx) {
printf("Error while creating eNB RX thread\n");
exit(-1);
}
if (error_code_eNB_tx) {
printf("Error while creating eNB TX thread\n");
exit(-1);
}
while (rrh_exit==0)
sleep(1);
}
} //while (rrh_exit==0)
close(sockid);
rrh_eNB_thread_status = 0;
pthread_exit(&rrh_eNB_thread_status);
return(0);
}
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;
}
}
int main(int argc, char **argv)
{
pthread_t main_rrh_eNB_thread, main_rrh_UE_thread, main_rrh_proc_eNB_thread, main_rrh_proc_UE_thread, main_timer_proc_thread;
pthread_attr_t attr, attr_proc, attr_timer;
struct sched_param sched_param_rrh, sched_param_rrh_proc, sched_param_timer;
int error_code_eNB, error_code_UE, error_code_proc_eNB, error_code_proc_UE, error_code_timer;
int i;
int opt;
int nsecs=0, rt_period=0;
rrh_desc_t rrh;
struct itimerspec timer;
rrh.time_req.tv_sec = 0;
rrh.time_req.tv_nsec = 0;
rrh.eNB_port = RRH_eNB_PORT;
strcpy(rrh.eNB_dest_ip,RRH_eNB_DEST_IP);
rrh.UE_port = RRH_UE_PORT;
strcpy(rrh.UE_dest_ip ,RRH_UE_DEST_IP);
nsecs = 0;
while ((opt = getopt(argc, argv, "t:rE:U:")) != -1) {
switch (opt) {
case 't':
rt_period = atoi(optarg);
RT_FLAG=1;
NRT_FLAG=0;
break;
case 'r':
rt_period = DEFAULT_PERIOD_NS;
RT_FLAG=1;
NRT_FLAG=0;
break;
case 'E':
strcpy(rrh.eNB_dest_ip,optarg);
break;
case 'U':
strcpy(rrh.UE_dest_ip,optarg);
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-d nsecs]\n", argv[0]);
exit(-1);
}
}
// if (optind >= argc) {
// fprintf(stderr, "Expected argument after options\n");
// exit(EXIT_FAILURE);
// }
// setup the timer (1s delay, 1s reload)
timer.it_value.tv_sec = rt_period/1000000000;
timer.it_value.tv_nsec = rt_period%1000000000;
timer.it_interval.tv_sec = rt_period/1000000000;
timer.it_interval.tv_nsec = rt_period%1000000000;
// to make a graceful exit when ctrl-c is pressed
signal(SIGSEGV, signal_handler);
signal(SIGINT, signal_handler);
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_init(&attr_timer);
sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-2);
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);
pthread_attr_setschedparam(&attr_timer,&sched_param_timer);
pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-2);
for (i=0; i<4; i++) {
pthread_mutex_init(&sync_eNB_mutex[i],NULL);
pthread_cond_init(&sync_eNB_cond[i],NULL);
pthread_mutex_init(&sync_UE_mutex[i],NULL);
pthread_cond_init(&sync_UE_cond[i],NULL);
}
pthread_mutex_init(&timer_mutex,NULL);
error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)&rrh);
error_code_UE = pthread_create(&main_rrh_UE_thread, &attr, rrh_UE_thread, (void *)&rrh);
error_code_proc_UE = pthread_create(&main_rrh_proc_UE_thread, &attr_proc, rrh_proc_UE_thread, NULL);
error_code_proc_eNB = pthread_create(&main_rrh_proc_eNB_thread, &attr_proc, rrh_proc_eNB_thread, NULL);
error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timer);
if (error_code_eNB) {
printf("Error while creating eNB thread\n");
exit(-1);
}
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);
}
if (error_code_proc_eNB) {
printf("Error while creating eNB proc thread\n");
exit(-1);
}
if (error_code_timer) {
printf("Error while creating timer proc thread\n");
exit(-1);
}
printf("TYPE <CTRL-C> TO TERMINATE\n");
while (rrh_exit==0)
sleep(1);
//pthread_join(main_rrh_eNB_thread,&rrh_eNB_thread_status);
return 0;
}
[*]
[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
[*] Fri Jan 29 16:34:46 2016
[*]
[dumpfile] "/tmp/openair_dump_rrh.vcd"
[dumpfile_mtime] "Fri Jan 29 16:20:55 2016"
[dumpfile_size] 224259458
[savefile] "/home/guepe/openairinterface5g_rrh/openairinterface5g/targets/RT/USER/rrh.gtkw"
[timestart] 31315875900
[size] 1004 1028
[pos] 926 -1
*-17.429794 31316090054 -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] 261
[sst_expanded] 1
[sst_vpaned_height] 278
@24
[color] 1
variables.hw_frame_rx[63:0]
[color] 1
variables.hw_subframe_rx[63:0]
@28
[color] 1
functions.eNB_rx
functions.eNB_rx_sleep
[color] 3
functions.trx_read_rf
[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
@24
variables.pck_rx[63:0]
variables.rx_ts[63:0]
@c00024
variables.tx_seq_num[63:0]
@28
(0)variables.tx_seq_num[63:0]
(1)variables.tx_seq_num[63:0]
(2)variables.tx_seq_num[63:0]
(3)variables.tx_seq_num[63:0]
(4)variables.tx_seq_num[63:0]
(5)variables.tx_seq_num[63:0]
(6)variables.tx_seq_num[63:0]
(7)variables.tx_seq_num[63:0]
(8)variables.tx_seq_num[63:0]
(9)variables.tx_seq_num[63:0]
(10)variables.tx_seq_num[63:0]
(11)variables.tx_seq_num[63:0]
(12)variables.tx_seq_num[63:0]
(13)variables.tx_seq_num[63:0]
(14)variables.tx_seq_num[63:0]
(15)variables.tx_seq_num[63:0]
(16)variables.tx_seq_num[63:0]
(17)variables.tx_seq_num[63:0]
(18)variables.tx_seq_num[63:0]
(19)variables.tx_seq_num[63:0]
(20)variables.tx_seq_num[63:0]
(21)variables.tx_seq_num[63:0]
(22)variables.tx_seq_num[63:0]
(23)variables.tx_seq_num[63:0]
(24)variables.tx_seq_num[63:0]
(25)variables.tx_seq_num[63:0]
(26)variables.tx_seq_num[63:0]
(27)variables.tx_seq_num[63:0]
(28)variables.tx_seq_num[63:0]
(29)variables.tx_seq_num[63:0]
(30)variables.tx_seq_num[63:0]
(31)variables.tx_seq_num[63:0]
(32)variables.tx_seq_num[63:0]
(33)variables.tx_seq_num[63:0]
(34)variables.tx_seq_num[63:0]
(35)variables.tx_seq_num[63:0]
(36)variables.tx_seq_num[63:0]
(37)variables.tx_seq_num[63:0]
(38)variables.tx_seq_num[63:0]
(39)variables.tx_seq_num[63:0]
(40)variables.tx_seq_num[63:0]
(41)variables.tx_seq_num[63:0]
(42)variables.tx_seq_num[63:0]
(43)variables.tx_seq_num[63:0]
(44)variables.tx_seq_num[63:0]
(45)variables.tx_seq_num[63:0]
(46)variables.tx_seq_num[63:0]
(47)variables.tx_seq_num[63:0]
(48)variables.tx_seq_num[63:0]
(49)variables.tx_seq_num[63:0]
(50)variables.tx_seq_num[63:0]
(51)variables.tx_seq_num[63:0]
(52)variables.tx_seq_num[63:0]
(53)variables.tx_seq_num[63:0]
(54)variables.tx_seq_num[63:0]
(55)variables.tx_seq_num[63:0]
(56)variables.tx_seq_num[63:0]
(57)variables.tx_seq_num[63:0]
(58)variables.tx_seq_num[63:0]
(59)variables.tx_seq_num[63:0]
(60)variables.tx_seq_num[63:0]
(61)variables.tx_seq_num[63:0]
(62)variables.tx_seq_num[63:0]
(63)variables.tx_seq_num[63:0]
@1401200
-group_end
@24
variables.hw_frame[63:0]
variables.hw_subframe[63:0]
@28
[color] 1
functions.eNB_tx
functions.eNB_tx_sleep
[color] 7
functions.trx_read
[color] 3
functions.trx_write_rf
@24
variables.txcnt[63:0]
variables.pck_tx[63:0]
variables.tx_ts[63:0]
@25
variables.rx_seq_num_prv[63:0]
@24
variables.rx_seq_num[63:0]
variables.hw_cnt_rx[63:0]
variables.lhw_cnt_rx[63:0]
[color] 3
variables.cnt[63:0]
[pattern_trace] 1
[pattern_trace] 0
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \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"
#include "rt_wrapper.h"
#include "rrh_gw_externs.h"
#include "log_if.h"
#include "log_extern.h"
#include "vcd_signal_dumper.h"
/*****************************************************************************************
* ---------- *
* ------- RRH_BBU_IF ------- RRH_RF_IF -------USRP - COTS_UE- *
* - BBU - --------------- - RRH - ------------- -------BLADERF ---------- *
* ------- ------- -------EXMIMO *
* --------- *
* -------ETH_IF - EMU_UE- *
* --------- *
*****************************************************************************************/
/* local IP/MAC address is detected*/
char rrh_ip[20] = "0.0.0.0";
unsigned char rrh_mac[20] = "0:0:0:0:0:0";
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;
/* flag 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;
uint8_t loopback_flag=0;
uint8_t measurements_flag=0;
/* Default operation as RRH:
- there are neither eNB nor UE modules
- no RF hardware is specified (NONE_IF)
- default ethernet interface is local */
uint8_t num_eNB_mod=0;
uint8_t num_UE_mod=0;
char* if_name="lo";
uint8_t eth_mode=ETH_UDP_MODE;
rrh_module_t *enb_array;
rrh_module_t *ue_array;
openair0_vtimestamp hw_counter=0;
char rf_config_file[1024];
static void debug_init(void);
static void get_options(int argc, char *argv[]);
static void print_help(void);
/*!\fn static rrh_module_t new_module(unsigned int id);
* \brief creation of a eNB/UE module
* \param[in] module id
* \return module
* \note
* @ingroup _oai
*/
static rrh_module_t new_module(unsigned int id);
/*!\fn static int get_address(char* if_name, uint8_t flag);
* \brief retrieves IP address from the specified network interface
* \param[in] name of network interface
* \return 0
* \note
* @ingroup _oai
*/
static int get_address(char* if_name, uint8_t flag);
int main(int argc, char **argv) {
unsigned int i;
rf_config_file[0]='\0';
/* 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);
/* create modules based on input arguments */
if (eNB_flag==1){
enb_array=(rrh_module_t*)malloc(num_eNB_mod*sizeof(rrh_module_t));
for(i=0;i<num_eNB_mod;i++){
enb_array[i]=new_module(i);//enb_array[i]=new_module(i, get_RF_interfaces(&hardware_target));
config_BBU_mod(&enb_array[i],RT_flag,NRT_flag);
LOG_I(RRH,"[eNB %d] module(s) created (out of %u) \n",i,num_eNB_mod);
}
}
if (UE_flag==1){
ue_array=(rrh_module_t*)malloc(num_UE_mod*sizeof(rrh_module_t));
for(i=0;i<num_UE_mod;i++){
ue_array[i]=new_module(i);
config_UE_mod(&ue_array[i],RT_flag,NRT_flag);
LOG_I(RRH,"[UE %d] module(s) created (out of %u)\n",i, num_UE_mod);
}
}
printf("TYPE <CTRL-C> TO TERMINATE\n");
while (rrh_exit==0)
sleep(1);
return EXIT_SUCCESS;
}
static rrh_module_t new_module (unsigned int id) {
rrh_module_t rrh_mod;
openair0_config_t openair0_cfg;
rrh_mod.id=id;
rrh_mod.loopback=loopback_flag;
rrh_mod.measurements=measurements_flag;
/* each module is associated with an ethernet device */
rrh_mod.eth_dev.type=NONE_DEV;
rrh_mod.eth_dev.transp_type=NONE_TP;
/* ethernet device is functioning within RRH */
rrh_mod.eth_dev.host_type=RRH_HOST;
/* */
rrh_mod.eth_dev.openair0_cfg = (openair0_config_t*)malloc(sizeof(openair0_config_t));
memset(rrh_mod.eth_dev.openair0_cfg,0,sizeof(openair0_config_t));
/* get IP and MAC address */
get_address(if_name,eth_mode);
if(eth_mode==ETH_UDP_MODE) {
openair0_cfg.my_addr = &rrh_ip[0];
openair0_cfg.my_port = rrh_port;
LOG_I(RRH,"UDP mode selected for ethernet.\n");
} else if (eth_mode==ETH_RAW_MODE) {
openair0_cfg.my_addr = (char*)&rrh_mac[0];
openair0_cfg.my_port = rrh_port;
LOG_I(RRH,"RAW mode selected for ethernet.\n");
}
/* */
eth_params_t *eth_params = (eth_params_t*)malloc(sizeof(eth_params_t));
memset(eth_params, 0, sizeof(eth_params_t));
eth_params->local_if_name = if_name;
eth_params->transp_preference = eth_mode;
/* ethernet device initialization */
if (openair0_transport_load(&rrh_mod.eth_dev, &openair0_cfg,eth_params)<0) {
LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n");
exit(-1);
}
/* allocate space and specify associated RF device */
openair0_device *oai_dv = (openair0_device *)malloc(sizeof(openair0_device));
memset(oai_dv,0,sizeof(openair0_device));
rrh_mod.devs=oai_dv;
rrh_mod.devs->type=NONE_DEV;
rrh_mod.devs->transp_type=NONE_TP;
rrh_mod.devs->host_type=RRH_HOST;
return rrh_mod;
}
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) {
vcd_signal_dumper_init("/tmp/openair_dump_rrh.vcd");
}
}
static void get_options(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "xvhlte:n:u:g:r:m:i:f:")) != -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 'i':
if (optarg) {
if_name=strdup(optarg);
printf("RRH interface name is set to %s\n", if_name);
}
break;
case 'm':
eth_mode=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 'f':
if (optarg){
if ((strcmp("null", optarg) == 0) || (strcmp("NULL", optarg) == 0)) {
printf("no configuration filename is provided\n");
}
else if (strlen(optarg)<=1024){
// rf_config_file = strdup(optarg);
strcpy(rf_config_file,optarg);
}else {
printf("Configuration filename is too long\n");
exit(-1);
}
}
break;
case 't':
/* When measurements are enabled statistics related to TX/RX time are printed */
measurements_flag=1;
break;
case 'h':
print_help();
exit(-1);
default: /* '?' */
//fprintf(stderr, "Usage: \n", argv[0]);
exit(-1);
}
}
}
static int get_address(char* if_name, uint8_t flag) {
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "if_name" */
strncpy(ifr.ifr_name, if_name, IFNAMSIZ-1);
if (flag==ETH_UDP_MODE) {
if ( ioctl(fd, SIOCGIFADDR, &ifr)<0 ) {
perror("IOCTL:");
exit(-1);
}
snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
LOG_I(RRH,"%s: IP address: %s\n",if_name,rrh_ip);
} else if (flag==ETH_RAW_MODE) {
if ( ioctl(fd, SIOCGIFHWADDR, &ifr)<0 ) {
perror("IOCTL:");
exit(-1);
}
ether_ntoa_r ((struct ether_addr *)ifr.ifr_hwaddr.sa_data, (char*)rrh_mac);
LOG_I(RRH,"%s: MAC address: %s\n",if_name,rrh_mac);
}
close(fd);
return 0;
}
static void print_help(void) {
puts("Usage: \n");
puts(" sudo -E chrt 99 ./rrh -n1 -g6 -v -t -i lo -m1");
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 -i set the RRH interface (default lo)\n");
puts("\t -m set ethernet mode to be used by RRH, valid options: (1:raw, 0:udp) \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 -h display info\n");
}
void *timer_proc(void *arg) {
timer_t timerid;
struct itimerspec *timer= (struct itimerspec *)arg ; // the timer data structure
struct itimerspec old_value;
#ifdef DEADLINE_SCHEDULER
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-30000;//(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
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);
LOG_I(RRH,"Timer has started!\n");
timer_settime (timerid, 0, timer, &old_value);
while (!rrh_exit) {
sleep(1);
}
timer_delete(timerid);
return (0);
}
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_CNT, hw_counter);//USED ELSEWHERE
}
}
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;
}
}
void exit_fun(const char* s) {
if (s != NULL) {
printf("%s %s() Exiting RRH: %s\n",__FILE__, __FUNCTION__, s);
}
rrh_exit = 1;
exit (-1);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \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 /* default value is calculated for 25 PRB */
#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 with an ethernet device (device of ETH_IF)
and optionally with a RF device (device type can be USRP_B200/USRP_X300/BLADERF_IF/EXMIMO_IF/NONE_IF)
UE modules will always have RF device type NONE_IF */
typedef struct {
/*! \brief module id */
uint8_t id;
/*! \brief! loopback flag */
uint8_t loopback;
/*! \brief measurement flag */
uint8_t measurements;
/*! \brief module's ethernet device */
openair0_device eth_dev;
/*! \brief pointer to RF module's device (pointer->since it's optional) */
openair0_device *devs;
}rrh_module_t;
/*! \fn void timer_signal_handler(int sig)
* \brief this function
* \param[in] signal type
* \return none
* \note
* @ingroup _oai
*/
void timer_signal_handler(int);
/*! \fn void *timer_proc(void *arg)
* \brief this function
* \param[in]
* \param[out]
* \return
* \note
* @ingroup _oai
*/
void *timer_proc(void *);
/*! \fn void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag,uint8_t NRT_flag)
* \brief receive and apply configuration to modules' optional device
* \param[in] *mod_enb pointer to module
* \param[in] RT_flag real time flag
* \return none
* \note
* @ingroup _oai
*/
void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag);
/*! \fn void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag)
* \brief this function
* \param[in] *mod_ue pointer to module
* \param[in]
* \return none
* \note
* @ingroup _oai
*/
void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag, uint8_t NRT_flag);
void signal_handler(int sig);
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \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 char rf_config_file[1024];
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;
extern pthread_mutex_t timer_mutex;
#endif
......@@ -263,7 +263,7 @@ endif
# Check if libpgm is installed and use it if found instead of the unreliable
# multicast
ifeq ($(PGM_FOUND), 1)
CFLAGS += $(PGM_CFLAGS) -DENABLE_PGM_TRANSPORT
CFLAGS += $(PGM_CFLAGS)
LIBS += $(PGM_LIBS)
endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment