diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 10c29cfc1e6d4f1b0e29cc2747d036ca4ebd6c7b..e4aa519f841c97efaeb1014f1b426f35b6a2f119 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -392,7 +392,7 @@ elseif (${RF_BOARD} STREQUAL "ETHERNET")
   set(HW_SOURCE ${HW_SOURCE}
     ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
     )
-  set(LOWLATENCY False)
+  set(LOWLATENCY True)
   
 elseif (${RF_BOARD} STREQUAL "CPRIGW")
   set(HW_SOURCE ${HW_SOURCE}
@@ -1558,6 +1558,7 @@ add_executable(lte-softmodem
   ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
   ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
   ${OPENAIR_TARGETS}/COMMON/create_tasks.c
+  ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
   ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
   ${OPENAIRCN_DIR}/NAS/UE/nas_ue_task.c
   ${GTPU_need_ITTI}
@@ -1591,6 +1592,7 @@ add_executable(lte-softmodem-nos1
   ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
   ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
   ${OPENAIR_TARGETS}/COMMON/create_tasks.c
+  ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
   #${OPENAIR2_DIR}/RRC/NAS/nas_config.c # enable if you want rrc to mount ip interface
   #${OPENAIR2_DIR}/RRC/NAS/rb_config.c
   ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
@@ -1725,7 +1727,8 @@ 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}/RT/USER/rt_wrapper.c
+  ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c		
   ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c 
   ${HW_SOURCE}
   )
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c
index 62b380fddbd41f0b3db1b062940d6db6ec76f9bf..a1223e6ca56bbee22580c647efb65d44868cc9a0 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.c
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.c
@@ -92,6 +92,8 @@ const char* eurecomVariablesNames[] = {
   "diff2",
   "hw_subframe",
   "hw_frame",
+  "hw_subframe_rx",
+  "hw_frame_rx",
   "txcnt",
   "rxcnt",
   "trx_ts",
@@ -103,6 +105,8 @@ const char* eurecomVariablesNames[] = {
   "hw_cnt_tx",
   "lhw_cnt_tx",
   "pck_rx",
+  "pck_tx",
+  "cnt",
   "dummy_dump",
   "itti_send_msg",
   "itti_poll_msg",
@@ -150,6 +154,8 @@ const char* eurecomFunctionsNames[] = {
   "eNB_rx_sleep",
   "eNB_tx_sleep",
   "eNB_proc_sleep",
+  "trx_read_rf",
+  "trx_write_rf",
 
   /* PHY signals  */
   "ue_synch",
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h
index 825b05d53576f30a03bfa9353e84a5c453a037f6..7ec2e2445eae99edaf3ec91adbabd7ccb1e7ed3f 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.h
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.h
@@ -64,6 +64,8 @@ typedef enum {
   VCD_SIGNAL_DUMPER_VARIABLES_DIFF,
   VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME,
   VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME,
+  VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME_RX,
+  VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME_RX,
   VCD_SIGNAL_DUMPER_VARIABLES_TXCNT,
   VCD_SIGNAL_DUMPER_VARIABLES_RXCNT,
   VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS,
@@ -75,6 +77,8 @@ typedef enum {
   VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT,
   VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT,
   VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK,
+  VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK,
+  VCD_SIGNAL_DUMPER_VARIABLES_CNT,
   VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP,
   VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG,
   VCD_SIGNAL_DUMPER_VARIABLE_ITTI_POLL_MSG,
@@ -116,8 +120,7 @@ typedef enum {
   VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_TX,
   VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX,
 
-  /* RRH signals  */
- 
+  /* RRH signals  */ 
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX,
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX,
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,
@@ -125,6 +128,8 @@ typedef enum {
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP,
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP,
   VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_SLEEP,
+  VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF,
+  VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF,
 
   /* PHY signals  */
   VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,
diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
index 97817e6eac23d587ee38f50757fbfe4396960bc9..6ebf709ec9d725bdcab9ea2fafe0430bf9ab1ba8 100644
--- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
+++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
@@ -185,7 +185,7 @@ int trx_brf_set_gains(openair0_device* device) {
 
 }
 
-int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
+int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg) {
 
   int status;
   int card=0;
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
new file mode 100644
index 0000000000000000000000000000000000000000..63f086ff1d5416329c96ba31de19140304a9fdcb
--- /dev/null
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -0,0 +1,64 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+   Contact Information
+   OpenAirInterface Admin: openair_admin@eurecom.fr
+   OpenAirInterface Tech : openair_tech@eurecom.fr
+   OpenAirInterface Dev  : openair4g-devel@eurecom.fr
+
+   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+/*! \file common_lib.c 
+ * \brief common APIs for different RF frontend device 
+ * \author HongliangXU, Navid Nikaein
+ * \date 2015
+ * \version 0.2
+ * \company Eurecom
+ * \maintainer:  navid.nikaein@eurecom.fr
+ * \note
+ * \warning
+ */
+#include <stdio.h>
+#include "common_lib.h"
+
+
+int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
+  
+#ifdef ETHERNET 
+  device->type=ETH_IF; 
+  device->func_type = BBU_FUNC;
+  openair0_dev_init_eth(device, openair0_cfg);
+  printf(" openair0_dev_init_eth ...\n");
+#elif EXMIMO
+  device->type=EXMIMO_IF;
+  openair0_dev_init_exmimo(device, openair0_cfg);
+  printf("openair0_dev_init_exmimo...\n");
+#elif OAI_USRP
+  device->type=USRP_IF;
+  openair0_dev_init_usrp(device, openair0_cfg);
+  printf("openair0_dev_init_usrp ...\n");
+#elif OAI_BLADERF  
+  device->type=BLADERF_IF;
+  openair0_dev_init_bladerf(device, openair0_cfg);	
+  printf(" openair0_dev_init_bladerf ...\n");   
+#endif 
+   
+}
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index dc9f30f4dfb99eb3fee16b5fec8a31d54f73c1d3..a6851b0dbe89e7c511e804c5697ace51a31b45ba 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -134,7 +134,13 @@ typedef struct {
 
 
 
-/*!\brief device type */
+/*!\brief interface types that apply to modules (RRH_BBU/RRH_UE) created in RRH (rrh_gw.c)
+          and are defined with respect to the RF device that is present in RRH
+          -RRH_BBU modules have two devices, one is by default ETHERNET (will have ETH_IF) and the other one is a
+	  RF device (EXMIMO,USRP,BLADERF) or no device (NONE_IF).
+          -RRH_UE modules have two devices one is by default ETHERNET (will have ETH_IF) 
+	  and the other one by default not present so it will have NONE_IF
+ */
 typedef enum {
   MIN_DEV_TYPE = 0,
   /*!\brief device is ETH */
@@ -152,10 +158,10 @@ typedef enum {
 } dev_type_t;
 
 
-/*!\brief  type */
+/*!\brief  openair0 device host type */
 typedef enum {
   MIN_FUNC_TYPE = 0,
- /*!\brief device functions within a  BBU */
+ /*!\brief device functions within a BBU */
   BBU_FUNC,
  /*!\brief device functions within a RRH */
   RRH_FUNC,
@@ -264,23 +270,20 @@ extern "C"
 #endif
 
 /*! \brief Initialize Openair RF target. It returns 0 if OK */
-int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
-  //int openair0_stop(int card);
-
-//ETHERNET
-/*! \brief Initialize Openair ETHERNET target. It returns 0 if OK */
-int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg);
-  //int openair0_stop_eth(int card);
-  //int openair0_set_gains_eth(openair0_device* device, openair0_config_t *openair0_cfg);
-  //int openair0_set_frequencies_eth(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
-
-//USPRP
+  int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
+  
+  //USRP
 /*! \brief Get the current timestamp of USRP */
-openair0_timestamp get_usrp_time(openair0_device *device);
-
+  openair0_timestamp get_usrp_time(openair0_device *device);
 /*! \brief Set the RX frequency of USRP RF TARGET */
-int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
-
+  int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
+  
+//extern
+/*! \brief Initialize Openair ETHERNET target. It returns 0 if OK */
+  int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg);
+  int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg);
+  int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg);
+  int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg);
 /*@}*/
 
 #ifdef __cplusplus
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
index 9f299fa58e0d2ee4384c3d0be5d25e84fbe3e584..6dd457d9b5f25d628070a44e7afda55aa54477de 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
@@ -26,7 +26,7 @@
    Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
 
  *******************************************************************************/
-/*! \fileethernet_lib.c 
+/*! \file ethernet_lib.c 
  * \brief API to stream I/Q samples over standard ethernet
  * \author Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
  * \date 2015
@@ -52,132 +52,208 @@
 #include "common_lib.h"
 #include "ethernet_lib.h"
 
+//#define DEBUG 1
 
 int num_devices_eth = 0;
 int dest_addr_len[MAX_INST];
 char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
 
 
-/* Initialization of UDP Socket to communicate with one destination */
-int ethernet_socket_init(openair0_device *device) {
-
-  int i = 0;
-  eth_state_t *eth = (eth_state_t*)device->priv;
-  int Mod_id = device->Mod_id;
+/*! \fn static int eth_socket_init(openair0_device *device)
+* \brief initialization of UDP Socket to communicate with one destination
+* \param[in] *device openair device for which the socket will be created
+* \param[out]
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup  _oai
+*/
+static int eth_socket_init(openair0_device *device);
+
+/*! \fn static int eth_set_dev_conf(openair0_device *device)
+* \brief 
+* \param[in] *device openair device 
+* \param[out]
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup  _oai
+*/
+static int eth_set_dev_conf(openair0_device *device);
+
+/*! \fn static int eth_get_dev_conf(openair0_device *device)
+* \brief
+* \param[in] *device openair device
+* \param[out]
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup  _oai
+*/
+static int eth_get_dev_conf(openair0_device *device);
+
+
+
+int trx_eth_start(openair0_device *device) {
   
-  // struct sockaddr_in *dest = &dest_addr[Mod_id];
-  char str[INET_ADDRSTRLEN];
-  const char *dest_ip;
-  int dest_port;
+  /* initialize socket */
+  if (eth_socket_init(device)!=0) {
+    return -1;
+  }
   
-  if (device->func_type == RRH_FUNC ){
-    dest_ip   = device->openair0_cfg.my_ip;   
-    dest_port = device->openair0_cfg.my_port;
-    printf("[RRH] ip addr %s port %d\n",dest_ip, dest_port);
+  /* RRH gets openair0 device configuration BBU sets openair0 device configuration*/
+  if (device->func_type == BBU_FUNC) {
+    return eth_set_dev_conf(device);
   } else {
-    dest_ip   = device->openair0_cfg.remote_ip;
-    dest_port = device->openair0_cfg.remote_port;
-    printf("[BBU] ip addr %s port %d\n",dest_ip, dest_port);
+    return eth_get_dev_conf(device);
   }
+
+  return 0;
+}
+
+
+int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {	
+  
+  int n_written=0,i;
+  uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
+  eth_state_t *eth = (eth_state_t*)device->priv;
+  int Mod_id = device->Mod_id;
+  int sendto_flag =0;
+  sendto_flag|=MSG_DONTWAIT;
+  
+  for (i=0;i<cc;i++) {	
+    /* buff[i] points to the position in tx buffer where the payload to be sent is
+       buff2 points to the position in tx buffer where the packet header will be placed */
+    void *buff2 = (void*)(buff[i]-header_size); 
     
-  /* Open RAW socket to send on */
-  if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
-    perror("ETHERNET: Error opening socket");
-    exit(0);
+    /* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
+    int32_t temp0 = *(int32_t *)buff2;
+    openair0_timestamp  temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
+    
+    n_written = 0;
+    
+    *(int16_t *)(buff2 + sizeof(int16_t))=1+(i<<1);
+    *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
+    
+    /* printf("[RRH]write mod_%d %d , len %d, buff %p antenna %d\n",
+       Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
+    
+    while(n_written < nsamps) {
+      /* Send packet */
+      if ((n_written += sendto(eth->sockfd[Mod_id],
+			       buff2, 
+			       (nsamps<<2)+header_size,
+			       0,
+			       (struct sockaddr*)&eth->dest_addr[Mod_id],
+			       dest_addr_len[Mod_id])) < 0) {
+	perror("ETHERNET WRITE");
+	exit(-1);
+      }
+    }
+
+#if DEBUG
+    printf("Buffer head TX: nu=%d an_id=%d ts%d samples_send=%d i=%d data=%x\n",
+	   *(int16_t *)buff2,
+	   *(int16_t *)(buff2 + sizeof(int16_t)),
+	   *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
+	   n_written>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
+#endif
+
+    /* tx buffer values restored */  
+    *(int32_t *)buff2 = temp0;
+    *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
   }
+  return n_written;
+  
+}
 
-  /* initialize destination address */
-  for (i=0; i< MAX_INST; i++)  
-    bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
+int trx_eth_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
 
- // bzero((void *)dest,sizeof(struct sockaddr_in));
-  eth->dest_addr[Mod_id].sin_family = AF_INET;
-  inet_pton(AF_INET,dest_ip,&(eth->dest_addr[Mod_id].sin_addr.s_addr));
-  eth->dest_addr[Mod_id].sin_port=htons(dest_port);
-  dest_addr_len[Mod_id] = sizeof(struct sockaddr_in);
-  inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
+  int bytes_received=0;
+  int block_cnt=0;
+  int ret=0,i;
+  uint16_t  header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
+
+  eth_state_t *eth = (eth_state_t*)device->priv;
+  int Mod_id = device->Mod_id;
   
-  /* if RRH, then I am the server, so bind */
-  if (device->func_type == RRH_FUNC ){    
-    if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&eth->dest_addr[Mod_id], dest_addr_len[Mod_id])<0) {
-      perror("ETHERNET: Cannot bind to socket");
-      exit(0);
-    }else {
-      printf("[RRH] binding mod_%d to %s:%d\n",Mod_id,str,ntohs(eth->dest_addr[Mod_id].sin_port));
+  for (i=0;i<cc;i++) {
+    /* buff[i] points to the position in rx buffer where the payload to be received will be placed
+       buff2 points to the position in rx buffer where the packet header will be placed */
+    void *buff2 = (void*)(buff[i]-header_size);
+    
+    /* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
+    int32_t temp0 = *(int32_t *)buff2;
+    openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
+    
+    bytes_received=0;
+    block_cnt=0;
+    ret=0;
+    
+    /* printf("[RRH] read mod_%d %d,len %d, buff %p antenna %d\n",
+       Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
+    
+    while(bytes_received < (int)((nsamps<<2))) {
+      ret=recvfrom(eth->sockfd[Mod_id],
+		   buff2+bytes_received,
+		   (nsamps<<2)+header_size-bytes_received,
+		   0,//MSG_DONTWAIT,
+                 (struct sockaddr *)&eth->dest_addr[Mod_id],
+		   (socklen_t *)&dest_addr_len[Mod_id]);
+      
+      if (ret==-1) {
+	if (errno == EAGAIN) {
+	  perror("ETHERNET READ: ");
+	  return((nsamps<<2) + header_size);
+	} else if (errno == EWOULDBLOCK) {
+	  block_cnt++;
+	  usleep(10);
+	  
+	  if (block_cnt == 100) return(-1);
+	}
+      } else {
+	bytes_received+=ret;
+      }
     }
+
+#if DEBUG   
+    printf("Buffer head RX: nu=%d an_id=%d ts%d samples_recv=%d i=%d data=%x\n",
+	   *(int16_t *)buff2,
+	   *(int16_t *)(buff2 + sizeof(int16_t)),
+	   *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
+	   ret>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
+#endif  
+
+    /* store the timestamp value from packet's header */
+    *timestamp =  *(openair0_timestamp *)(buff2 + sizeof(int32_t));
     
-  }else {
-    printf("[BBU] Connecting to %s:%d\n",str,ntohs(eth->dest_addr[Mod_id].sin_port));
+    /* tx buffer values restored */  
+    *(int32_t *)buff2 = temp0;
+    *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
   }
+  return nsamps;
   
-  return 0;
 }
 
-void ethernet_socket_opt (openair0_device *device){
+void trx_eth_end(openair0_device *device) {
 
   eth_state_t *eth = (eth_state_t*)device->priv;
-  int Mod_id=device->Mod_id;
-  
-  int sndbuf_size=0, rcvbuf_size=0;      
-  socklen_t optlen;    
-  /* chang the MTU of the eth interface */ 
-  struct ifreq ifr; 
-  
-  optlen = sizeof(int);  
-  
-  if (getsockopt(eth->sockfd[Mod_id],  
-                 SOL_SOCKET,  
-                 SO_SNDBUF,  
-                 &sndbuf_size,&optlen))   
-    printf("error:getsockopt()\n");  
-  
-  if (getsockopt(eth->sockfd[Mod_id],  
-                 SOL_SOCKET,  
-                 SO_RCVBUF,  
-                 &rcvbuf_size,&optlen))
-    printf("error:getsockopt()\n"); 
-
-  printf( "sndbuf_size= %d bytes rcvbuf_size= %d bytes\n", sndbuf_size,
-	  rcvbuf_size); 
-
-  ifr.ifr_addr.sa_family = AF_INET;
-  //iap->ifa_name is bond1:xx
-  strncpy(ifr.ifr_name, DEFAULT_IF, sizeof(ifr.ifr_name));
-  ifr.ifr_mtu = device->openair0_cfg.samples_per_packet*5; 
-  if (ioctl(eth->sockfd[Mod_id], SIOCSIFMTU, (caddr_t)&ifr)  < 0 )
-    perror ("Can't set the MTU");
-  else 
-    printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
-  
+  int Mod_id = device->Mod_id;
+  /*destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
+  if ( close(eth->sockfd[Mod_id]) <0 ) {
+    perror("ETHERNET: Failed to close socket");
+    exit(0);
+   } else {
+    printf("[RRH] socket for mod_id %d has been successfully closed.\n",Mod_id);
+   }
+ 
 }
 
 
-int trx_eth_set_dev_conf(openair0_device *device) {
+int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
 
   int 	       Mod_id = device->Mod_id;
   eth_state_t *eth = (eth_state_t*)device->priv;
-  void 	      *msg;
-  ssize_t     msg_len;
-
-  
-  /* send to RRH (server) required configuration parameters:
-     -number of downlink RBs (so that frame/packet size can be set accordingly)
-     -rx_num_0channels
-     -tx_num_channels
-     -rx_freq
-     -tx_freq
-     -rxg_mode[4]	
-     -rx_gain
-     -tx_gain
-     -rx_bw
-     -tx_bw
-     -autocal */ 
-  
-  msg=malloc(sizeof(openair0_config_t));
-  msg_len=sizeof(openair0_config_t);
-  memcpy(msg,(void*)&device->openair0_cfg,msg_len);	
-  
-  if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&eth->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1){
+ 
+  /* BBU sends a message to RRH */
+ if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&eth->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
     perror("ETHERNET: ");
     exit(0);
   }
@@ -187,44 +263,43 @@ int trx_eth_set_dev_conf(openair0_device *device) {
 
 
 
-int trx_eth_get_dev_conf(openair0_device *device) {
+int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
 
   eth_state_t   *eth = (eth_state_t*)device->priv;
   int 		Mod_id = device->Mod_id;
-  char 		str[INET_ADDRSTRLEN];
-  void 		*msg;
-  ssize_t	msg_len;
-  
-  msg=malloc(sizeof(openair0_config_t));
-  msg_len=sizeof(openair0_config_t);
 
-  /* receive from client (lte-softmodem)  */
+  /* RRH receives from BBU a message */
   if (recvfrom(eth->sockfd[Mod_id],
 	       msg,
 	       msg_len,
 	       0,
 	       (struct sockaddr *)&eth->dest_addr[Mod_id],
-	       (socklen_t *)&dest_addr_len[Mod_id])==-1){
+	       (socklen_t *)&dest_addr_len[Mod_id])==-1) {
     perror("ETHERNET: ");
     exit(0);
-  }
-		
-   memcpy((void*)&device->openair0_cfg,msg,msg_len);	
-   inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
-   device->openair0_cfg.remote_port =ntohs(eth->dest_addr[Mod_id].sin_port);
-   device->openair0_cfg.remote_ip=str;
-   //ethernet_socket_opt (device);
-   // printf("[RRH] write mod_%d %d to %s:%d\n",Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port));
-
+  }	
+ 
    return 0;
 }
 
-int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
+
+static int eth_set_dev_conf(openair0_device *device) {
 
   int 	       Mod_id = device->Mod_id;
   eth_state_t *eth = (eth_state_t*)device->priv;
- 
- if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&eth->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1){
+  void 	      *msg;
+  ssize_t      msg_len;
+
+  
+  /* a BBU client sents to RRH a set of configuration parameters (openair0_config_t)
+     so that RF front end is configured appropriately and
+     frame/packet size etc. can be set */ 
+  
+  msg=malloc(sizeof(openair0_config_t));
+  msg_len=sizeof(openair0_config_t);
+  memcpy(msg,(void*)&device->openair0_cfg,msg_len);	
+  
+  if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&eth->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
     perror("ETHERNET: ");
     exit(0);
   }
@@ -233,169 +308,40 @@ int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
 }
 
 
-
-int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
+static int eth_get_dev_conf(openair0_device *device) {
 
   eth_state_t   *eth = (eth_state_t*)device->priv;
   int 		Mod_id = device->Mod_id;
+  char 		str[INET_ADDRSTRLEN];
+  void 		*msg;
+  ssize_t	msg_len;
+  
+  msg=malloc(sizeof(openair0_config_t));
+  msg_len=sizeof(openair0_config_t);
 
-  /* receive from client (lte-softmodem)  */
+  /* RRH receives from BBU openair0_config_t */
   if (recvfrom(eth->sockfd[Mod_id],
 	       msg,
 	       msg_len,
 	       0,
 	       (struct sockaddr *)&eth->dest_addr[Mod_id],
-	       (socklen_t *)&dest_addr_len[Mod_id])==-1){
+	       (socklen_t *)&dest_addr_len[Mod_id])==-1) {
     perror("ETHERNET: ");
     exit(0);
   }
 		
- 
-   return 0;
-}
-
-
-int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id) {	
-	
-  int n_written;
-  uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
-  eth_state_t *eth = (eth_state_t*)device->priv;
-  int Mod_id = device->Mod_id;
-  int sendto_flag =0;
-  sendto_flag|=MSG_DONTWAIT;
-	
-  /* buff[antenna_id] points to the position in tx buffer where the payload to be sent is
-     buff2 points to the position in tx buffer where the packet header will be placed */
-  void *buff2 = (void*)(buff[antenna_id]-header_size); // (void*)((unsigned char *)buff[antenna_id]-header_size);
-
-  /* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
-  int32_t temp0 = *(int32_t *)buff2;
-  openair0_timestamp  temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-  
-  n_written = 0;
-  
-  *(int16_t *)(buff2 + sizeof(int16_t))=1+(antenna_id<<1);
-  *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
-	
-  /* printf("[RRH]write mod_%d %d , len %d, buff %p antenna %d\n",
-     Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
-	
-while(n_written < nsamps) {
-    /* Send packet */
-  if ((n_written += sendto(eth->sockfd[Mod_id],
-			   buff2, 
-                           (nsamps<<2)+header_size,
-                           0,
-                           (struct sockaddr*)&eth->dest_addr[Mod_id],
-                           dest_addr_len[Mod_id])) < 0) {
-    perror("ETHERNET WRITE");
-    exit(-1);
-    }
-  }
-
-/* printf("Buffer head TX: nu=%d an_id=%d ts%d byte_send=%d \n",		*(int16_t *)buff2,
-  *(int16_t *)(buff2 + sizeof(int16_t)),
-  *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
-  n_written>>2);*/
-  
-  /* tx buffer values restored */  
-  *(int32_t *)buff2 = temp0;
-  *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-  return n_written;
-
-}
-
-
-int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id) {
-
-  int bytes_received;
-  int block_cnt;
-  int ret;
-  uint16_t  header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
-
-  
-  /* buff[antenna_id] points to the position in rx buffer where the payload to be received will be placed
-     buff2 points to the position in rx buffer where the packet header will be placed */
-  void *buff2 = (void*)(buff[antenna_id]-header_size);
-  
-  /* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
-  int32_t temp0 = *(int32_t *)buff2;
-  openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-  
-  eth_state_t *eth = (eth_state_t*)device->priv;
-  int Mod_id = device->Mod_id;
-  
-  bytes_received=0;
-  block_cnt=0;
-
- /* printf("[RRH] read mod_%d %d,len %d, buff %p antenna %d\n",
-     Mod_id,eth->sockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
-	
-  while(bytes_received < (int)((nsamps<<2))) {
-    ret=recvfrom(eth->sockfd[Mod_id],
-                 buff2+bytes_received,
-                 (nsamps<<2)+header_size-bytes_received,
-                 0,//MSG_DONTWAIT,
-                 (struct sockaddr *)&eth->dest_addr[Mod_id],
-                 (socklen_t *)&dest_addr_len[Mod_id]);
-
-    if (ret==-1) {
-      if (errno == EAGAIN) {
-        perror("ETHERNET READ: ");
-        return((nsamps<<2) + header_size);
-      } else if (errno == EWOULDBLOCK) {
-        block_cnt++;
-        usleep(10);
-	
-        if (block_cnt == 100) return(-1);
-      }
-    } else {
-      bytes_received+=ret;
-    }
-  }
-  /*
-    printf("Buffer head RX: nu=%d an_id=%d ts%d byte_recv=%d\n",      *(int16_t *)buff2,
-    *(int16_t *)(buff2 + sizeof(int16_t)),
-    *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
-    ret>>2);*/
-  
-  /* store the timestamp value from packet's header */
-  *timestamp =  *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-  
-  /* tx buffer values restored */  
-  *(int32_t *)buff2 = temp0;
-  *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-  // printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
-  
-  return nsamps;
-  
-}
+   memcpy((void*)&device->openair0_cfg,msg,msg_len);	
+   inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
+   device->openair0_cfg.remote_port =ntohs(eth->dest_addr[Mod_id].sin_port);
+   device->openair0_cfg.remote_ip=str;
+   /*apply additional configuration*/
+   //ethernet_tune (device, RING_PAR);
+   // printf("[RRH] write mod_%d %d to %s:%d\n",Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port));
 
-int trx_eth_start(openair0_device *device){
-  
-  if (ethernet_socket_init(device)!=0) {
-    return -1;
-  }
-  
-  if (device->func_type == BBU_FUNC ) {
-    return trx_eth_set_dev_conf(device);
-  }
-  else{
-    return trx_eth_get_dev_conf(device);
-  }
-  return(0);
+   return 0;
 }
 
-int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int antenna_id, int flags) {
-  
-  return ethernet_write_data(device,timestamp,buff,nsamps,antenna_id);
-}
 
-int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int antenna_id) {
-  
-  return(ethernet_read_data(device,ptimestamp,buff,nsamps,antenna_id));
-  
-}
 
 int trx_eth_stop(int card) {
   return(0);
@@ -409,48 +355,173 @@ int trx_eth_set_gains(openair0_device* device, openair0_config_t *openair0_cfg)
   return(0);
 }
 
-
 int trx_eth_get_stats(openair0_device* device) {
-
   return(0);
-
 }
 
 int trx_eth_reset_stats(openair0_device* device) {
-
   return(0);
-
 }
 
-int openair0_set_gains(openair0_device* device, 
-		       openair0_config_t *openair0_cfg) {
-
-  return(0);
-}
 
-int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg, int dummy) {
+static int eth_socket_init(openair0_device *device) {
 
-  return(0);
-}
+  int i = 0;
+  eth_state_t *eth = (eth_state_t*)device->priv;
+  int Mod_id = device->Mod_id;  
+  char str[INET_ADDRSTRLEN];
+  const char *dest_ip;
+  int dest_port=0;
+  
+  if (device->func_type == RRH_FUNC ) {
+    dest_ip   = device->openair0_cfg.my_ip;   
+    dest_port = device->openair0_cfg.my_port;
+    printf("[RRH] ip addr %s port %d\n",dest_ip, dest_port);
+  } else {
+    dest_ip   = device->openair0_cfg.remote_ip;
+    dest_port = device->openair0_cfg.remote_port;
+    printf("[BBU] ip addr %s port %d\n",dest_ip, dest_port);
+  }
+    
+  /* Open RAW socket to send on */
+  if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+    perror("ETHERNET: Error opening socket");
+    exit(0);
+  }
 
+  /* initialize destination address */
+  for (i=0; i< MAX_INST; i++) {
+    bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
+  }
 
+ // bzero((void *)dest,sizeof(struct sockaddr_in));
+  eth->dest_addr[Mod_id].sin_family = AF_INET;
+  inet_pton(AF_INET,dest_ip,&(eth->dest_addr[Mod_id].sin_addr.s_addr));
+  eth->dest_addr[Mod_id].sin_port=htons(dest_port);
+  dest_addr_len[Mod_id] = sizeof(struct sockaddr_in);
+  inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
+  
+  /* if RRH, then I am the server, so bind */
+  if (device->func_type == RRH_FUNC ) {    
+    if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&eth->dest_addr[Mod_id], dest_addr_len[Mod_id])<0) {
+      perror("ETHERNET: Cannot bind to socket");
+      exit(0);
+    } else {
+      printf("[RRH] binding mod_%d to %s:%d\n",Mod_id,str,ntohs(eth->dest_addr[Mod_id].sin_port));
+    }
+    
+  } else {
+    printf("[BBU] Connecting to %s:%d\n",str,ntohs(eth->dest_addr[Mod_id].sin_port));
+  }
+  
+  return 0;
+}
 
-void trx_eth_end(openair0_device *device) {
 
+int ethernet_tune(openair0_device *device , eth_opt_t option) {
+  
   eth_state_t *eth = (eth_state_t*)device->priv;
-  int Mod_id = device->Mod_id;
-  /*destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
-  if ( close(eth->sockfd[Mod_id]) <0 ) {
-    perror("ETHERNET: Failed to close socket");
-    exit(0);
-   }else {
-    printf("[RRH] socket for mod_id %d has been successfully closed.",Mod_id);
-   }
- 
+  int Mod_id=device->Mod_id;
+  
+  unsigned int sndbuf_size=0, rcvbuf_size=0;
+  struct timeval snd_timeout, rcv_timeout;
+  struct ifreq ifr;   
+  char system_cmd[256]; 
+  char* if_name=DEFAULT_IF;
+
+  /****************** socket level options ************************/
+  if (option== SND_BUF_SIZE) {    /* transmit socket buffer size */   
+    if (setsockopt(eth->sockfd[Mod_id],  
+		   SOL_SOCKET,  
+		   SO_SNDBUF,  
+		   &sndbuf_size,sizeof(sndbuf_size))) {
+      perror("[ETHERNET] setsockopt()");
+    } else {
+      printf( "sndbuf_size= %d bytes\n", sndbuf_size); 
+    }     
+  } else if (option== RCV_BUF_SIZE) {  /* receive socket buffer size */   
+    if (setsockopt(eth->sockfd[Mod_id],  
+		   SOL_SOCKET,  
+		   SO_RCVBUF,  
+		   &rcvbuf_size,sizeof(rcvbuf_size))) {
+      perror("[ETHERNET] setsockopt()");
+    } else {     
+      printf( "rcvbuf_size= %d bytes\n", rcvbuf_size);    
+    }
+  } else if (option==RCV_TIMEOUT) {
+    rcv_timeout.tv_sec = 0;
+    rcv_timeout.tv_usec = 180;//less than rt_period
+    if (setsockopt(eth->sockfd[Mod_id],  
+		   SOL_SOCKET,  
+		   SO_RCVTIMEO,  
+		   (char *)&rcv_timeout,sizeof(rcv_timeout))) {
+      perror("[ETHERNET] setsockopt()");  
+    } else {   
+      printf( "rcv_timeout= %d usecs\n", rcv_timeout.tv_usec);  
+    }  
+  } else if (option==SND_TIMEOUT) {
+    snd_timeout.tv_sec = 0;
+    snd_timeout.tv_usec = 180;//less than rt_period
+    if (setsockopt(eth->sockfd[Mod_id],  
+		   SOL_SOCKET,  
+		   SO_SNDTIMEO,  
+		   (char *)&snd_timeout,sizeof(snd_timeout))) {
+      perror("[ETHERNET] setsockopt()");     
+    } else {
+      printf( "snd_timeout= %d usecs\n", snd_timeout.tv_usec);    
+    }
+  }
+  
+  /******************* interface level options  *************************/
+  else if (option==MTU_SIZE) {    /* change  MTU of the eth interface */ 
+    ifr.ifr_addr.sa_family = AF_INET;
+    strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
+    ifr.ifr_mtu =8960;
+    if (ioctl(eth->sockfd[Mod_id],SIOCSIFMTU,(caddr_t)&ifr) < 0 )
+      perror ("[ETHERNET] Can't set the MTU");
+    else 
+      printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
+  } else if (option==TX_Q_LEN) {    /* change TX queue length of eth interface */ 
+    ifr.ifr_addr.sa_family = AF_INET;
+    strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
+    ifr.ifr_qlen =3000 ;
+    if (ioctl(eth->sockfd[Mod_id],SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
+      perror ("[ETHERNET] Can't set the txqueuelen");
+    else 
+      printf("[ETHERNET] %s txqueuelen size has changed to %d\n",DEFAULT_IF,ifr.ifr_qlen);
+
+
+    /******************* device level options  *************************/
+  } else if (option==COALESCE_PAR) {  
+    if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs 3",DEFAULT_IF) > 0) {
+      system(system_cmd);
+      printf("[ETHERNET] Coalesce parameters %s\n",system_cmd);
+    } else {
+      perror("[ETHERNET] Can't set coalesce parameters\n");
+    }
+    
+  } else if (option==PAUSE_PAR ) {  
+    if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",DEFAULT_IF) > 0) {
+      system(system_cmd);
+      printf("[ETHERNET] Pause parameters %s\n",system_cmd);
+    } else {
+      perror("[ETHERNET] Can't set pause parameters\n");
+    }
+  } else if (option==RING_PAR ) {  
+    if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s rx 4096 tx 4096",DEFAULT_IF) > 0) {
+      system(system_cmd);
+      printf("[ETHERNET] Ring parameters %s\n",system_cmd);
+    } else {
+      perror("[ETHERNET] Can't set ring parameters\n");
+    }
+    
+  }
+  return 0;
 }
 
 
-int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg){
+
+int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg) {
 
   eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
   int card = 0;
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
index 8914ff580945431d35396e667debf52c11b92722..628fcb377c7f0fbdea48ad82bec3ab8f68b326dc 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
@@ -48,7 +48,7 @@
 #include <netinet/ether.h>
 
 #define MAX_INST        4
-#define DEFAULT_IF  "eth0"
+#define DEFAULT_IF  "lo"
 #define BUF_SIZ      8960 /*Jumbo frame size*/
 
 typedef struct {
@@ -103,21 +103,51 @@ struct eth_meta_data{
 };
 
 
+
+/*!\brief packet header */
 typedef struct {
-  /* packet's timestamp */
+  /*!\brief packet's timestamp */ 
   openair0_timestamp timestamp;
-  /* variable declared for alignment purposes (sample size=32 bit)  */
+  /*!\brief variable declared for alignment purposes (sample size=32 bit)  */
   int16_t not_used;
-  /* antenna port used to resynchronize*/
+  /*!\brief antenna port used to resynchronize */
   int16_t antenna_id;
 } header_t;
 
-
-
-int ethernet_socket_init(openair0_device *device);
-
-int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id);
-
-int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id);
-
-void ethernet_socket_opt (openair0_device *device);
+/*!\brief different options for ethernet tuning in socket and driver level */
+typedef enum {
+  MIN_OPT = 0,  
+  /*!\brief socket send buffer size in bytes */
+  SND_BUF_SIZE,
+  /*!\brief socket receive buffer size in bytes */
+  RCV_BUF_SIZE,
+  /*!\brief receiving timeout */
+  RCV_TIMEOUT,
+  /*!\brief sending timeout */
+  SND_TIMEOUT,
+  /*!\brief maximun transmission unit size in bytes */
+  MTU_SIZE,
+  /*!\brief TX queue length */
+  TX_Q_LEN,
+  /*!\brief RX/TX  ring parameters of ethernet device */
+  RING_PAR,
+  /*!\brief interruptions coalesence mechanism of ethernet device */
+  COALESCE_PAR,
+  /*!\brief pause parameters of ethernet device */
+  PAUSE_PAR,
+  MAX_OPT
+} eth_opt_t;
+
+
+
+/*! \fn int ethernet_tune (openair0_device *device, eth_opt_t option)
+* \brief this function allows you to configure certain ethernet parameters in socket or device level
+* \param[in] openair0 device which bears the socket
+* \param[in] name of parameter to configure
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup  _oai
+*/
+int ethernet_tune (openair0_device *device, eth_opt_t option);
+int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc) ;
+int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int cc);
diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
index 01eca4bf6abb28e16acd3344eb911748db4bea49..71c10090391a6cb4144bc5f8ffd9c5d01b42bde1 100644
--- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
+++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
@@ -247,7 +247,7 @@ int openair0_stop_without_reset(int card)
 #define MY_RF_MODE      (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
 #define RF_MODE_BASE    (LNA1ON + RFBBNORM)
 
-int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
+int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg) {
 
   // Initialize card
   //  exmimo_config_t         *p_exmimo_config;
diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
index d62497b262f8f12fa992cac335dd1fffbec48bf1..192ed503e2e3408170720f0476f4a5e25943424c 100644
--- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
+++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
@@ -154,7 +154,6 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
 
 static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc)
 {
-
    usrp_state_t *s = (usrp_state_t*)device->priv;
    int samples_received=0,i,j;
    int nsamps2;  // aligned to upper 32 or 16 byte boundary
@@ -182,31 +181,26 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
     // receive a single channel (e.g. from connector RF A)
     samples_received = s->rx_stream->recv(buff_tmp[0], nsamps, s->rx_md);
   }
-  
+
   // bring RX data into 12 LSBs for softmodem RX
   for (int i=0;i<cc;i++) {
-    for (int j=0; j<nsamps2; j++) {
+    for (int j=0; j<nsamps2; j++) {      
 #if defined(__x86_64__) || defined(__i386__)
 #ifdef __AVX2__
-
       ((__m256i *)buff[i])[j] = _mm256_srai_epi16(buff_tmp[i][j],4);
-
 #else
       ((__m128i *)buff[i])[j] = _mm_srai_epi16(buff_tmp[i][j],4);
-
 #endif
 #elif defined(__arm__)
-
       ((int16x8_t*)buff[i])[j] = vshrq_n_s16(buff_tmp[i][j],4);
-
 #endif
     }
-  }
-
+    }
   if (samples_received < nsamps) {
     printf("[recv] received %d samples out of %d\n",samples_received,nsamps);
     
   }
+
   //handle the error code
   switch(s->rx_md.error_code){
   case uhd::rx_metadata_t::ERROR_CODE_NONE:
@@ -225,6 +219,7 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
   s->rx_count += nsamps;
   s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
   *ptimestamp = s->rx_timestamp;
+
   return samples_received;
 }
 
@@ -334,7 +329,7 @@ int trx_usrp_reset_stats(openair0_device* device) {
 }
 
 
-int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg)
+int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg)
 {
   uhd::set_thread_priority_safe(1.0);
   usrp_state_t *s = (usrp_state_t*)malloc(sizeof(usrp_state_t));
@@ -499,6 +494,5 @@ int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cf
     s->tx_forward_nsamps = 90;
   if(is_equal(s->sample_rate, (double)7.68e6))
     s->tx_forward_nsamps = 50;
-
   return 0;
 }
diff --git a/targets/RT/USER/UE_transport_IQ.c b/targets/RT/USER/UE_transport_IQ.c
index f88e22dbfa1fb5f87604f48e238130ad74c5045f..e986046d811ebe5fab312889aebb47a52156f913 100644
--- a/targets/RT/USER/UE_transport_IQ.c
+++ b/targets/RT/USER/UE_transport_IQ.c
@@ -89,15 +89,8 @@ void 			*rrh_UE_thread_status;
 void *rx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx
 void *tx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx
 
-/*! \fn void create_UE_trx_threads( openair0_device *dev_ue, uint8_t RT_flag,uint8_t NRT_flag)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void create_UE_trx_threads( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) {
+
+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;
diff --git a/targets/RT/USER/eNB_transport_IQ.c b/targets/RT/USER/eNB_transport_IQ.c
index 43981257ec9f79b8b9d5c7d2e71420ca2161006d..eaad2ebb24f59118c4aae512b8682d45af14f81f 100644
--- a/targets/RT/USER/eNB_transport_IQ.c
+++ b/targets/RT/USER/eNB_transport_IQ.c
@@ -28,7 +28,7 @@
  *******************************************************************************/
 
 /*! \file eNB_transport_IQ.c
- * \brief eNB transport IQ sampels 
+ * \brief eNB transport IQ samples 
  * \author  Katerina Trilyraki, Navid Nikaein, Raymond Knopp
  * \date 2015
  * \version 0.1
@@ -53,158 +53,202 @@
 
 #define PRINTF_PERIOD    3750
 #define HEADER_SIZE      ((sizeof(int32_t) + sizeof(openair0_timestamp))>>2)
-//#undef LOWLATENCY
-/******************************************************************************
- **                               FUNCTION PROTOTYPES                        **
- ******************************************************************************/
-void *rrh_eNB_rx_thread(void *);
-void *rrh_eNB_tx_thread(void *);
-void *rrh_proc_eNB_thread(void *);
-void *rrh_eNB_thread(void *);
-void set_rt_period( openair0_config_t openair0_cfg);
-void check_dev_config( rrh_module_t *mod_enb);
-
-
-pthread_t	   main_rrh_eNB_thread;
-pthread_attr_t     attr, attr_proc;
-struct sched_param sched_param_rrh;
 
 pthread_cond_t          sync_eNB_cond[4];
 pthread_mutex_t         sync_eNB_mutex[4];
+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;
-int32_t		**tx_buffer_eNB, **rx_buffer_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
 
-int 	        	sync_eNB_rx[4]= {-1,-1,-1,-1};
-openair0_timestamp	timestamp_eNB_tx[4]= {0,0,0,0},timestamp_eNB_rx[4]= {0,0,0,0};
+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, prev_tx_pos=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 create_eNB_trx_threads( rrh_module_t *dev_enb, uint8_t RT_flag,uint8_t NRT_flag)
+
+
+/*! \fn void *rrh_eNB_rx_thread(void *arg)
  * \brief this function
  * \param[in]
- * \param[out]
- * \return
+ * \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
  */
-void create_eNB_trx_threads( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag){
+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 	i;
-  int 	error_code_eNB;
+  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;
-  
-  pthread_attr_init(&attr);
-  sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO);
-  pthread_attr_setschedparam(&attr,&sched_param_rrh);
-  pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
-  /*for (i=0; i<4; i++) {
-    pthread_mutex_init(&sync_eNB_mutex[i],NULL);
-    pthread_cond_init(&sync_eNB_cond[i],NULL);
-    }*/
-  
+    
   /* handshake with client to exchange parameters */
   mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port  make it plus_id
-  
-  memcpy((void*)&mod_enb->devs->openair0_cfg,(void *)&mod_enb->eth_dev.openair0_cfg,sizeof(openair0_config_t));
-  
-  /* update certain parameters */
-  if ( mod_enb->devs->type == EXMIMO_IF ) {
-    if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
-      mod_enb->devs->openair0_cfg.tx_delay = 8;
-    }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
-      mod_enb->devs->openair0_cfg.tx_delay = 5;
-    }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
-      mod_enb->devs->openair0_cfg.tx_delay = 6;
-    }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 256;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
-      mod_enb->devs->openair0_cfg.tx_delay = 8;
-    }
-  }
-  else if (mod_enb->devs->type == USRP_IF) {
-    if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
-      mod_enb->devs->openair0_cfg.tx_delay = 8;
-    }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ) {
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
-      mod_enb->devs->openair0_cfg.tx_delay = 5;
-    }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ) {
-      mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
-      mod_enb->devs->openair0_cfg.tx_delay = 6;
-    }
-  else if( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ) {
-    mod_enb->devs->openair0_cfg.samples_per_packet = 256;
-    mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
-    mod_enb->devs->openair0_cfg.tx_delay = 8;
-  }
-  }
-  else if (mod_enb->devs->type == BLADERF_IF) {
-    if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
-      mod_enb->devs->openair0_cfg.tx_delay = 8;
-   }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
-      mod_enb->devs->openair0_cfg.tx_delay = 5;
+ 
+ /* if a RF iterface is added to RRH module get the  configuration parameters sent from eNB  */
+  if (mod_enb->devs->type != NONE_IF ) {  
+
+    memcpy((void*)&mod_enb->devs->openair0_cfg,(void *)&mod_enb->eth_dev.openair0_cfg,sizeof(openair0_config_t));
+    
+    /* certain parameters have to be updated (calibration related)*/
+    if ( mod_enb->devs->type == EXMIMO_IF ) {
+      if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
+	mod_enb->devs->openair0_cfg.tx_delay = 5;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
+	mod_enb->devs->openair0_cfg.tx_delay = 6;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 256;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }
     }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
-      mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
-      mod_enb->devs->openair0_cfg.tx_delay = 6;
+    else if (mod_enb->devs->type == USRP_IF) {
+      if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
+	mod_enb->devs->openair0_cfg.tx_delay = 5;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
+	mod_enb->devs->openair0_cfg.tx_delay = 6;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 256;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }
     }
-    else if( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ){
-      mod_enb->devs->openair0_cfg.samples_per_packet = 256;
-     mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
-     mod_enb->devs->openair0_cfg.tx_delay = 8;
-    }           
- }  
-  
-  /* check sanity of received configuration parameters and print */
-  check_dev_config(mod_enb);
-  
-#ifndef ETHERNET
-    /* initialize and apply configuration to associated RF device */
+    else if(mod_enb->devs->type == BLADERF_IF) {
+      if ( mod_enb->devs->openair0_cfg.num_rb_dl == 100 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 175;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 50 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 2048;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 95;
+	mod_enb->devs->openair0_cfg.tx_delay = 5;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 25 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 1024;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 70;
+	mod_enb->devs->openair0_cfg.tx_delay = 6;
+      }
+      else if ( mod_enb->devs->openair0_cfg.num_rb_dl == 6 ) {
+	mod_enb->devs->openair0_cfg.samples_per_packet = 256;
+	mod_enb->devs->openair0_cfg.tx_forward_nsamps = 40;
+	mod_enb->devs->openair0_cfg.tx_delay = 8;
+      }           
+    }  
+    
+    /* check sanity of configuration parameters and print */
+    check_dev_config(mod_enb);    
+    
+    /* initialize and configure the RF device */
     if (openair0_device_init(mod_enb->devs, &mod_enb->devs->openair0_cfg)<0){
-    LOG_E(RRH,"Exiting, cannot initialize RF device.\n");
-    exit(-1);
+      LOG_E(RRH,"Exiting, cannot initialize RF device.\n");
+      exit(-1);
     }
     else {
       LOG_I(RRH,"RF device has been successfully initialized.\n");
+    }    
+
+    /* start RF device */
+    if (mod_enb->devs->type == EXMIMO_IF ) {
+      
+    } else {
+      if (mod_enb->devs->trx_start_func(mod_enb->devs)!=0)
+	LOG_E(RRH,"Unable to initiate RF device.\n");
     }
-    
-#endif
+    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);
@@ -212,16 +256,9 @@ void create_eNB_trx_threads( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT
   
 }
 
-/*! \fn void *rrh_eNB_thread(void *arg)
- * \brief this function
- * \param[in]
- * \param[out]
- * \return
- * \note
- * @ingroup  _oai
- */
-void *rrh_eNB_thread(void *arg)
-{
+
+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;
@@ -229,42 +266,35 @@ void *rrh_eNB_thread(void *arg)
   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 );
-    
-    
-    if (dev->devs->type != NONE_IF) {
-      set_rt_period(dev->eth_dev.openair0_cfg);
-    }
-    samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;    
+    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_I(RRH,"rx ch %d %p and tx ch %d %p\n", 
-	  dev->eth_dev.openair0_cfg.rx_num_channels,
-	  rx_buffer_eNB,
-	  dev->eth_dev.openair0_cfg.tx_num_channels,
-	  tx_buffer_eNB);
+    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 *)malloc(sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
-      memset(tmp,0,sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
-      rx_buffer_eNB[i]=( tmp + (HEADER_SIZE*sizeof(int32_t)) );  
-      LOG_I(RRH," rx ch %d %p |%p\n",i,rx_buffer_eNB[i],tmp);
+      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 *)malloc(sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
-      memset(tmp,0,sizeof(int32_t)*(samples_per_frame + HEADER_SIZE));
-      tx_buffer_eNB[i]=( tmp + (HEADER_SIZE*sizeof(int32_t)) );  
-      LOG_I(RRH," tx ch %d %p| %p \n", i,tx_buffer_eNB[i],tmp);
+      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++) {
@@ -277,20 +307,28 @@ void *rrh_eNB_thread(void *arg)
       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 */
+    }    
+    /* 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 LOWLATENCY
     error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev);
-    error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev);	
+    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);
@@ -313,29 +351,62 @@ void *rrh_eNB_thread(void *arg)
       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_IF) {
 
+      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 LOWLATENCY
+      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 );
-  }  //while (eNB_exit==0)
-
+  }  
+  
   rrh_eNB_thread_status = 0;
   pthread_exit(&rrh_eNB_thread_status);
   return(0);
 }
 
 
-
-/*! \fn void *rrh_eNB_rx_thread(void *arg)
- * \brief this function
- * \param[in]
- * \param[out]
- * \return
- * \note
- * @ingroup  _oai
- */
-void *rrh_eNB_rx_thread(void *arg){
+void *rrh_eNB_rx_thread(void *arg) {
 
   /* measuremnt related vars */
   struct timespec time0,time1,time2;
@@ -345,19 +416,23 @@ void *rrh_eNB_rx_thread(void *arg){
   struct timespec time_req_1us, time_rem_1us;
   rrh_module_t *dev = (rrh_module_t *)arg;
   ssize_t bytes_sent;
-  int i, spp ,pck_rx=0;
-  openair0_vtimestamp last_hw_counter=0;  //volatile int64_t
-  unsigned int samples_per_frame=0;
+  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;
 
-  //RTIME sleep_ns=1000;
   time_req_1us.tv_sec = 0;
   time_req_1us.tv_nsec =1000;  //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue
-  spp =  dev->eth_dev.openair0_cfg.samples_per_packet;
+  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;
+  next_rx_pos = spp_eth;
 
 #ifdef LOWLATENCY
   struct sched_attr attr;
@@ -369,248 +444,298 @@ void *rrh_eNB_rx_thread(void *arg){
   attr.sched_priority = 0;
 
   attr.sched_policy   = SCHED_DEADLINE;
-  attr.sched_runtime  = (0.1   *  100) * 10000; // 
-  attr.sched_deadline = rt_period;// 0.1   *  1000000; // 
-  attr.sched_period   = rt_period; //0.1   *  1000000; // each TX/RX thread has 
-
+  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) {
-
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 1 );
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT, hw_counter );
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT, last_hw_counter );
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK, pck_rx );
-
-    for (i=0; i<dev->eth_dev.openair0_cfg.rx_num_channels; i++){
-      if (!eNB_rx_started) {
-	eNB_rx_started=1; // set this flag to 1 to indicate that eNB started
-	if (RT_flag_eNB==1) {
-	  last_hw_counter=hw_counter;
-	}
-      } else {
-	if (RT_flag_eNB==1) {
-	  if (hw_counter > last_hw_counter+1) {
-	    printf("LR");
-	  } else {
-	    while (hw_counter < last_hw_counter+1){
-	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 1 );
-	      nanosleep(&time_req_1us,&time_rem_1us);
-	      //rt_sleep_ns(sleep_ns);
-	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 0 );
-	    } 
+  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_IF) {	
+	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);
       
-      /* LOG_I(RRH,"send for%d at %d with %d |%d|%d| \n",i,rx_pos,timestamp_eNB_rx[i],((timestamp_eNB_rx[i]+spp)%samples_per_frame),next_rx_pos );
-			
-      if ((timestamp_UE_tx[i]%samples_per_frame < next_rx_pos) && (UE_tx_started==1)) {
-	printf("eNB underflow\n");
-	if (NRT_flag_eNB==1) {
-	  while ((timestamp_UE_tx[i]%samples_per_frame) < spp)
-          nanosleep(&time_req_1us,&time_rem_1us);
-	}
-      }	
-      if (((rx_pos)< timestamp_UE_tx[i]%samples_per_frame) && (next_rx_pos > (timestamp_UE_tx[i]%samples_per_frame)) && (UE_tx_started==1)) {
-	printf("eNB underflow\n");
-	if (NRT_flag_eNB==1) {
-	  while (next_rx_pos > (timestamp_UE_tx[i]%samples_per_frame))
-          nanosleep(&time_req_1us,&time_rem_1us);
-	}
-	}*/
 
+      if (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{
+	} else {
 	  rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
 	  LOG_I(RRH,"rx_buffer_eNB[i][rx_pos]=%d ,rx_pos=%d\n",rx_buffer_eNB[i][rx_pos],rx_pos);	
 	}
-      }
-
-      rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
-
-      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
-      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_TS, timestamp_eNB_rx[i]&0xffffffff );
-      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); 
-      
-      //LOG_D(RRH," rx_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_eNB_rx[i]);	 
-      if ((bytes_sent = dev->eth_dev.trx_write_func (&dev->eth_dev,
-						     timestamp_eNB_rx[i],
-						     rx_eNB,
-						     spp,
-						     i,
-						     0))<0){
-	perror("RRH eNB : sendto for RX");
-      }
+       }
+       
+       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_IF) {
+	 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_IF) {
+	 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\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time);
+	   }
+	 }
+	 
+	 memcpy(&time0,&time2,sizeof(struct timespec));
+       }
+       
+       if (loopback == 1 ) {
+	 pthread_mutex_lock(&sync_eNB_mutex[i]);
+	 sync_eNB_rx[i]--;
+	 pthread_mutex_unlock(&sync_eNB_mutex[i]);
+       }
+       
+       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 
     
-      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
-
-      timestamp_eNB_rx[i]+=spp;
-      last_hw_counter=hw_counter;
-
-      if (measurements == 1 ) {
-
-	clock_gettime(CLOCK_MONOTONIC,&time2);
-	
-	if (trace_cnt++ > 10) {
-	  total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec);
-	  if (total_rx_time < 0)
-	    total_rx_time=1000000000-total_rx_time;
-	  
-	  if ((total_rx_time > 0) && (total_rx_time < 1000000000)) {
-	    trial++;
-	    if (total_rx_time < min_rx_time)
-	      min_rx_time = total_rx_time;
-	    if (total_rx_time > max_rx_time){
-	      max_rx_time = total_rx_time;
-	      LOG_I(RRH,"Max value %d update at rx_position %d \n",total_rx_time,timestamp_eNB_rx[i]);
-	    }
-	    average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1);
-	  }
-	  if (s_period++ == PRINTF_PERIOD) {
-	    s_period=0;
-	    LOG_I(RRH,"Average eNB RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time);
-	  }
-	}
-	
-	memcpy(&time0,&time2,sizeof(struct timespec));
-      }
-
-      if (loopback == 1 ){
-	pthread_mutex_lock(&sync_eNB_mutex[i]);
-	sync_eNB_rx[i]--;
-	pthread_mutex_unlock(&sync_eNB_mutex[i]);
-      }
-      
-    }//for each antenna
+    subframe++;
+    s_cnt=0;
     
-    rx_pos += spp;    
-    pck_rx++;
-    next_rx_pos=(rx_pos+spp);
-
+    /* 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;
-
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 0 );
+    /* wrap around subframe number */       
+    if (subframe == 10 ) {
+      subframe = 0; 
+      frame++;
+    }   
+   
+    
   }  //while (eNB_exit==0)
-  return(0);
+  return 0;
 }
 
 
-/*! \fn void *rrh_eNB_tx_thread(void *arg)
- * \brief this function
- * \param[in]
- * \param[out]
- * \return
- * \note
- * @ingroup  _oai
- */
-void *rrh_eNB_tx_thread(void *arg){
+void *rrh_eNB_tx_thread(void *arg) {
 
   struct timespec time0a,time0,time1,time2;
 
   rrh_module_t *dev = (rrh_module_t *)arg;
   struct timespec time_req_1us, time_rem_1us;
   ssize_t bytes_received;
-  int spp,i;
+  int i;
   openair0_timestamp last_hw_counter=0;
-  unsigned int samples_per_frame=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 LOWLATENCY
   struct sched_attr attr;
   unsigned int flags = 0;
-
+  
   attr.size = sizeof(attr);
   attr.sched_flags = 0;
   attr.sched_nice = 0;
   attr.sched_priority = 0;
-
+  
   attr.sched_policy   = SCHED_DEADLINE;
-  attr.sched_runtime  = (0.1  *  100) * 10000; // 
-  attr.sched_deadline = rt_period;//0.1  *  1000000; // 
-  attr.sched_period   = rt_period;//0.1  *  1000000; // each TX/RX thread has 
-
+  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	
-
-  tx_pos=0;
-  time_req_1us.tv_sec = 0;
-  time_req_1us.tv_nsec = 1000;
-  spp = dev->eth_dev.openair0_cfg.samples_per_packet;
+  
+  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;
+  //tx_pos_rf=spp_rf*dev->devs->openair0_cfg.tx_delay;
+  
   loopback = dev->loopback;
   measurements = dev->measurements;
   
-  while (rrh_exit == 0) {
-
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 1 );		
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT, hw_counter );
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT, last_hw_counter );
-
-    if (measurements == 1 )
-      clock_gettime(CLOCK_MONOTONIC,&time0a);
-
-    for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++){
-      if (!eNB_tx_started) {
-	eNB_tx_started=1; // set this flag to 1 to indicate that eNB started
-	if (RT_flag_eNB==1) {
-	last_hw_counter=hw_counter;
-	}
-      } else {
-	if (RT_flag_eNB==1) {
-	  if (hw_counter > last_hw_counter+1) {
-	    printf("LT");
-	  } else {
-	    while (hw_counter < last_hw_counter+1){
-	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 1 );
-	      nanosleep(&time_req_1us,&time_rem_1us);
-	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 0 );
-	    }
-	  }
-	}
+  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);
       }
-
-      if (measurements == 1 ) 
-	clock_gettime(CLOCK_MONOTONIC,&time1);
-
-      tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];			
+      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 (dev->devs->type == NONE_IF) {  
+		VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT, hw_counter );
+		VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT, last_hw_counter );    
+		
+		if (!eNB_tx_started) {
+		eNB_tx_started=1; // set this flag to 1 to indicate that eNB started
+		if (RT_flag_eNB==1) {
+		last_hw_counter=hw_counter;
+		}
+		} else {
+		if (RT_flag_eNB==1) {
+		if (hw_counter > last_hw_counter+1) {
+		printf("LT");
+		} else {
+		while ((hw_counter < last_hw_counter+1)) {
+		VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 1 );
+		nanosleep(&time_req_1us,&time_rem_1us);
+		VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP, 0 );
+		}
+		}
+		}
+		}
+		}    */
+      
+      if (measurements == 1 ) 	clock_gettime(CLOCK_MONOTONIC,&time1); 
+      for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++) tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];	//RF!!!!!		
+      
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos );
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
-      bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev,
-						&timestamp_eNB_tx[i],
-						tx_eNB,
-						spp,
-						i);		
+      
+      /* 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 );	
-      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_eNB_tx[i]&0xffffffff );
-      if (NRT_flag_eNB==1) {
-	nrt_eNB_counter[i]++;
+      
+      if (dev->devs->type != NONE_IF) {  
+	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,
+					0)<0){
+	  perror("RRH eNB : USRP write");
+	}
+	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 0 );
       }
-      prev_tx_pos=tx_pos;
-      tx_pos += spp;   
-
-      if (tx_pos >= samples_per_frame)
-	tx_pos -= samples_per_frame;
       
-      last_hw_counter=hw_counter;
-	
+      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_tx&0xffffffff ); 
+      
+            
+      if (dev->devs->type == NONE_IF)	last_hw_counter=hw_counter;
+    
+    
       if (loopback ==1 ) { 
 	while (sync_eNB_rx[i]==0)
 	  nanosleep(&time_req_1us,&time_rem_1us);
@@ -618,30 +743,47 @@ void *rrh_eNB_tx_thread(void *arg){
 	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));
+      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);
     }
 
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 0 );
-  }
-  return(0);
+    /* 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;
 }
 
-//needs to be fixed 
-void set_rt_period( openair0_config_t openair0_cfg){
+
+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);
-  //only in case of  NRT with emulated UE
-  //create_timer_thread();  
+  LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period);	
 }
 
 
-void check_dev_config( rrh_module_t *mod_enb) {
+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);
@@ -656,7 +798,7 @@ void check_dev_config( rrh_module_t *mod_enb) {
  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]);
+ 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");
  
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index 1867e6181d725c1266855277b6c3ab0e423f9f30..2faa4e796d04f2a32cb008ddc8190d7cdeccaf61 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -2991,23 +2991,7 @@ openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
 
   openair0.func_type = BBU_FUNC;
   openair0_cfg[0].log_level = glog_level;
-  
-#ifdef ETHERNET 
-  openair0.type=ETH_IF; // not used for the moment
-  openair0.func_type = BBU_FUNC;
-  openair0_dev_init_eth(&openair0, &openair0_cfg[0]);
-#else 
-#ifdef EXMIMO
-  openair0.type=EXMIMO_IF;
-  printf("Setting the HW to EXMIMO and initializing openair0 ...\n");
-#elif OAI_USRP
-  openair0.type=USRP_IF;
-  printf("Setting the HW to USRP and initializing openair0 ...\n");
-#elif OAI_BLADERF  
-  openair0.type=BLADERF_IF;	
-  printf("Setting the HW to BLADERF and initializing openair0 ...\n");   
-#endif 
- 
+
   if ((mode!=loop_through_memory) && 
       (openair0_device_init(&openair0, &openair0_cfg[0]) <0)) {
     printf("Exiting, cannot initialize device\n");
@@ -3015,8 +2999,7 @@ openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
   }
   else if (mode==loop_through_memory) {    
   }
-#endif 
-
+ 
   printf("Done\n");
 
   mac_xface = malloc(sizeof(MAC_xface));
diff --git a/targets/RT/USER/rrh.c b/targets/RT/USER/rrh.c
index 7e4e54935181e61db785cebda0d328de8a7fa10a..ff4776754b0229a786f390377eebaf7811babfaa 100644
--- a/targets/RT/USER/rrh.c
+++ b/targets/RT/USER/rrh.c
@@ -58,8 +58,8 @@
 #define RRH_UE_PORT 51000
 #define RRH_UE_DEST_IP "127.0.0.1"
 
-#define FRAME_MAX_SIZE 307200
-#define DEFAULT_PERIOD_NS 133333
+#define FRAME_MAX_SIZE 307200//76800
+#define DEFAULT_PERIOD_NS 133333//200000
 
 #define START_CMD 1
 #define PRINTF_PERIOD 3750
diff --git a/targets/RT/USER/rrh.gtkw b/targets/RT/USER/rrh.gtkw
index 8eb2333489cbb44d23282d99fa22fa76257a6557..22a5a9f575b252528a9bb701ba3940c826296adc 100644
--- a/targets/RT/USER/rrh.gtkw
+++ b/targets/RT/USER/rrh.gtkw
@@ -1,25 +1,29 @@
 [*]
 [*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
-[*] Thu Jul  9 09:53:25 2015
+[*] Thu Sep 17 14:23:43 2015
 [*]
 [dumpfile] "/tmp/openair_dump_rrh.vcd"
-[dumpfile_mtime] "Thu Jul  9 09:52:29 2015"
-[dumpfile_size] 170586112
-[savefile] "/home/sud/openair4G/targets/RT/USER/eNB2.gtkw"
-[timestart] 16177999000
-[size] 1535 876
+[dumpfile_mtime] "Thu Sep 17 14:21:43 2015"
+[dumpfile_size] 636509125
+[savefile] "/home/guepe/openair4G/targets/RT/USER/rrh.gtkw"
+[timestart] 17746655400
+[size] 1855 1056
 [pos] -1 -1
-*-17.749426 16178576148 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+*-15.826077 17746846200 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [sst_width] 224
 [signals_width] 230
 [sst_expanded] 1
-[sst_vpaned_height] 230
+[sst_vpaned_height] 287
+@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] 7
-functions.trx_write
+functions.trx_write_rf
 @c00024
 variables.rxcnt[63:0]
 @28
@@ -89,23 +93,27 @@ variables.rxcnt[63:0]
 (63)variables.rxcnt[63:0]
 @1401200
 -group_end
+@24
+variables.pck_rx[63:0]
+variables.hw_frame[63:0]
+variables.hw_subframe[63:0]
 @28
 [color] 1
 functions.eNB_tx
 functions.eNB_tx_sleep
+functions.trx_read_rf
+[color] 7
+functions.trx_write
 [color] 7
 functions.trx_read
 @24
 variables.txcnt[63:0]
 variables.rx_ts[63:0]
 variables.tx_ts[63:0]
-variables.pck_rx[63:0]
 variables.hw_cnt_rx[63:0]
 variables.lhw_cnt_rx[63:0]
-variables.hw_frame[63:0]
-@28
-functions.eNB_tm
-@29
-functions.eNB_trx
+@25
+[color] 3
+variables.cnt[63:0]
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/targets/RT/USER/rrh_gw.c b/targets/RT/USER/rrh_gw.c
index 204dc6d0b6c85acc17ee486437966f2751b53125..2ff213b14708ef412f3191c26f28459233b6a1f3 100644
--- a/targets/RT/USER/rrh_gw.c
+++ b/targets/RT/USER/rrh_gw.c
@@ -60,17 +60,17 @@
 #include "log_extern.h"
 #include "vcd_signal_dumper.h"
 
-//#undef LOWLATENCY
+/*****************************************************************************************
+ *                                                                        ----------     *
+ *     -------    RRH_BBU_IF    -------    RRH_RF_IF     -------USRP      - COTS_UE-     *
+ *     - BBU - ---------------  - RRH -  -------------   -------BLADERF   ----------     *
+ *     -------                  -------                  -------EXMIMO                   *
+ *                                                                        ---------      *
+ *                                                       -------ETH_IF    - EMU_UE-      *
+ *                                                                        ---------      *                              
+ *****************************************************************************************/
+
 
-/******************************************************************************
- **                               FUNCTION PROTOTYPES                        **
- ******************************************************************************/
-static void debug_init(void);
-static void get_options(int argc, char *argv[]);
-static void print_help(void);
-static void get_RFinterfaces(void);
-static rrh_module_t new_module(unsigned int id);
-int get_ip_address(char* if_name);
 
 char rrh_ip[20] = "192.168.12.242"; // there is code to detect the my ip address
 int  rrh_port = 50000; // has to be an option
@@ -98,25 +98,51 @@ uint8_t         measurements_flag=0;
 
 /* Default operation as RRH:
    - there are neither eNB nor UE modules
-   - no RF device is asscociated with RRH */
+   - no RF hardware is specified (NONE_IF)
+   - default ethernet interface is local */
 uint8_t 	    num_eNB_mod=0;
 uint8_t 	    num_UE_mod=0;
 uint8_t 	    num_EXMIMO_mod=0;
 uint8_t 	    num_USRP_mod=0;
 uint8_t             hardware_target=NONE_IF;
+char*               if_name="lo";
 
 rrh_module_t 	        *enb_array;
 rrh_module_t            *ue_array;
 
-pthread_mutex_t         timer_mutex;
 openair0_vtimestamp 	hw_counter=0;
-unsigned int		rt_period=0;
-struct itimerspec       timerspec;
 
-char* if_name="lo";
 
-int main(int argc, char **argv) {
 
+
+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_ip_address(char* if_name)
+ * \brief retrieves IP address from the specified network interface
+ * \param[in] name of network interface
+ * \return 0 
+ * \note
+ * @ingroup  _oai
+ */
+static int get_ip_address(char* if_name);
+
+
+
+
+
+int main(int argc, char **argv) {
+  
   unsigned int i;
   
   /* parse input arguments */
@@ -125,58 +151,16 @@ int main(int argc, char **argv) {
   debug_init();
   /* */
   set_latency_target();
-  /*make a graceful exit when ctrl-c is pressed */
+  /* make a graceful exit when ctrl-c is pressed */
   signal(SIGSEGV, signal_handler);
   signal(SIGINT, signal_handler);
-  /*probe RF front end devices interfaced to RRH */
-  // get_RFinterfaces();
   
-
-#ifdef ETHERNET 
- 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;
-  
-
-  //#ifndef LOWLATENCY
-  pthread_attr_t 	attr_timer;
-  struct sched_param 	sched_param_timer;
-  
-  pthread_attr_init(&attr_timer);
-  sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO);
-  pthread_attr_setschedparam(&attr_timer,&sched_param_timer);
-  pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO);
-   
-  pthread_mutex_init(&timer_mutex,NULL);
-
-  error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec);
-  LOG_I(RRH,"[SCHED] FIFO scheduling applied to timer thread \n");		
-  /*#else 
-  error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec);
-  LOG_I(RRH,"[SCHED] deadline scheduling applied to timer thread \n");		
-  #endif*/	
-  
-  if (error_code_timer) {
-    LOG_E(RRH,"Error while creating timer proc thread\n");
-    exit(-1);
-  }
-#endif
-
   /* 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));	
-      create_eNB_trx_threads(&enb_array[i],RT_flag,NRT_flag);
+      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);		
     }
   }
@@ -184,7 +168,7 @@ int main(int argc, char **argv) {
     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);
-      create_UE_trx_threads(&ue_array[i],RT_flag,NRT_flag);			
+      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);
     }
   }
@@ -194,22 +178,10 @@ int main(int argc, char **argv) {
   while (rrh_exit==0)
     sleep(1);
 
-  //close sockets 
-  
   return EXIT_SUCCESS;
 }
 
 
-
-
-/*!\fn openair0_device new_module (unsigned int id, dev_type_t type)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
 static rrh_module_t new_module (unsigned int id) {
 
   rrh_module_t 	  	rrh_mod;
@@ -221,7 +193,9 @@ static rrh_module_t new_module (unsigned int id) {
 
   /* each module is associated with an ethernet device */
   rrh_mod.eth_dev.type=ETH_IF;
+  /* ethernet device is functioning within RRH */
   rrh_mod.eth_dev.func_type=RRH_FUNC; 
+  /* specify IP address */
   get_ip_address(if_name);
   openair0_cfg.my_ip=&rrh_ip[0];
   openair0_cfg.my_port=rrh_port;
@@ -231,8 +205,8 @@ static rrh_module_t new_module (unsigned int id) {
     LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n");
     exit(-1);
   }
- 
-  /* specify associated RF device */
+
+  /* allocate space and specify associated RF device */
   openair0_device *oai_dv = (openair0_device *)malloc(sizeof(openair0_device));
   memset(oai_dv,0, sizeof(openair0_device));
 
@@ -257,121 +231,8 @@ static rrh_module_t new_module (unsigned int id) {
   return rrh_mod;
 }
 
-
-
-
-/*! \fn void *timer_proc(void *arg)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void *timer_proc(void *arg) {
-
-  timer_t             timerid;    
-  struct itimerspec   *timer= (struct itimerspec *)arg ; // the timer data structure
-  struct itimerspec   *old_value;
-
-  /* 
-#ifdef LOWLATENCY
-  struct sched_attr attr;
-  unsigned int flags = 0;
-  
-  attr.size = sizeof(attr);
-  attr.sched_flags = 0;
-  attr.sched_nice = 0;
-  attr.sched_priority = 0;
-  
-  attr.sched_policy   = SCHED_DEADLINE;
-  attr.sched_runtime  =  (0.1  *  100) * 10000; // 
-  attr.sched_deadline =  rt_period-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);
-}
-
-
-/*! \fn void timer_signal_handler(int sig)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void timer_signal_handler(int sig) {
-  
-  if (sig == SIGALRM) {
-    pthread_mutex_lock(&timer_mutex);
-    hw_counter ++;
-    pthread_mutex_unlock(&timer_mutex);
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, hw_counter);
-  }
-}
-
-
-/*! \fn void signal_handler(int sig)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void signal_handler(int sig) {
-  
-  void *array[10];
-  size_t size;
-  
-  if (sig==SIGSEGV) {
-    // get void*'s for all entries on the stack
-    size = backtrace(array, 10);
-    
-    // print out all the frames to stderr
-    fprintf(stderr, "Error: signal %d:\n", sig);
-    backtrace_symbols_fd(array, size, 2);
-    exit(-1);
-  } else {
-    printf("trying to exit gracefully...\n");
-    rrh_exit = 1;
-  }
-}
-
-
-/*! \fn void debug_init(void)
- * \brief this function
- * \param[in]
- * \param[out]
- * \return
- * \note
- * @ingroup  _oai
- */
 static void debug_init(void) {
-	
+  
   // log initialization
   logInit();
   set_glog(glog_level,  glog_verbosity);
@@ -384,17 +245,10 @@ static void debug_init(void) {
   if (ouput_vcd) {
     vcd_signal_dumper_init("/tmp/openair_dump_rrh.vcd");
     
-}
+  }
 }
 
-/*!\fn void get_options(int argc, char *argv[])
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
+
 static void get_options(int argc, char *argv[]) {
 
   int 	opt;
@@ -457,45 +311,35 @@ static void get_options(int argc, char *argv[]) {
 
 }
 
-/*!\fn void print_help(void)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-int get_ip_address(char* if_name) {
+static int get_ip_address(char* if_name) {
   
   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 "eth0" */
+  
+  /* I want IP address attached to "if_name" */
   strncpy(ifr.ifr_name, if_name, IFNAMSIZ-1);
+  
+  if ( ioctl(fd, SIOCGIFADDR, &ifr)<0 ) {
+    perror("IOCTL:");
+    exit(-1);
+  } 
+  
+  close(fd);
+  
+  /* display result */
+  snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
+  LOG_I(RRH,"Got IP address %s from interface %s\n", rrh_ip,if_name);
 
- ioctl(fd, SIOCGIFADDR, &ifr);
-
- close(fd);
-
- /* display result */
- snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
- printf("Got IP address %s from interface %s\n", rrh_ip,if_name);
- return 0;
+  return 0;
 }
 
-/*!\fn void print_help(void)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
+
 static void print_help(void) {
 
   puts("Usage: \n");
@@ -504,7 +348,7 @@ static void print_help(void) {
   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 eth0)\n");
+  puts("\t -i set the RRH interface (default lo)\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");
@@ -516,84 +360,90 @@ static void print_help(void) {
 
 }
 
-/*! \fn void exit_fun(const char* s)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void exit_fun(const char* s)
-{
-  if (s != NULL) {
-    printf("%s %s() Exiting RRH: %s\n",__FILE__, __FUNCTION__, s);
-  }
-  rrh_exit = 1;
-  exit (-1);
-}
 
+void *timer_proc(void *arg) {
 
-/*! \fn static void get_RFinterfaces(void)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-static void get_RFinterfaces(void) {
+  timer_t             timerid;    
+  struct itimerspec   *timer= (struct itimerspec *)arg ; // the timer data structure
+  struct itimerspec   *old_value;
 
-  EXMIMO_flag=1;
-  USRP_flag=1;
-  num_EXMIMO_mod=1;
-  num_USRP_mod=1;
+  
+#ifdef LOWLATENCY
+  struct sched_attr attr;
+  unsigned int flags = 0;
+  
+  attr.size = sizeof(attr);
+  attr.sched_flags = 0;
+  attr.sched_nice = 0;
+  attr.sched_priority = 0;
+  
+  attr.sched_policy   = SCHED_DEADLINE;
+  attr.sched_runtime  =  (0.1  *  100) * 10000; // 
+  attr.sched_deadline =  rt_period-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);
 }
 
 
-/*!\fn void create_timer_thread(void)
-* \brief this function
-* \param[in]
-* \param[out]
-* \return
-* \note
-* @ingroup  _oai
-*/
-void create_timer_thread() {
+void timer_signal_handler(int sig) {
   
-  int 			error_code_timer;
-  pthread_t 		main_timer_proc_thread;
+  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
+  }
+}
 
-  LOG_I(RRH,"Creating timer thread with rt period  %d ns.\n",rt_period);
- 
-  /* setup the timer to generate an interrupt:
-     -for the first time in (sample_per_packet/sample_rate) ns
-     -and then every (sample_per_packet/sample_rate) ns */
-  timerspec.it_value.tv_sec =     rt_period/1000000000;
-  timerspec.it_value.tv_nsec =    rt_period%1000000000;
-  timerspec.it_interval.tv_sec =  rt_period/1000000000;
-  timerspec.it_interval.tv_nsec = rt_period%1000000000;
-  
-  pthread_mutex_init(&timer_mutex,NULL);
-  
-#ifndef LOWLATENCY
-  pthread_attr_t 	attr_timer;
-  struct sched_param 	sched_param_timer;
+
+void signal_handler(int sig) {
   
-  pthread_attr_init(&attr_timer);
-  sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-1);
-  pthread_attr_setschedparam(&attr_timer,&sched_param_timer);
-  pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-1);
-  error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec);
-  LOG_I(RRH,"[SCHED] FIFO scheduling applied to timer thread \n");		
-#else 
-  error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec);
-  LOG_I(RRH,"[SCHED] deadline scheduling applied to timer thread \n");		
-#endif	
+  void *array[10];
+  size_t size;
   
-  if (error_code_timer) {
-    LOG_E(RRH,"Error while creating timer proc thread\n");
+  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);
+}
+
+
diff --git a/targets/RT/USER/rrh_gw.h b/targets/RT/USER/rrh_gw.h
index 7d6d89b9d1a56216d8fe332ea3ef5f17f1ae944b..37852c3b11fdcd8788221b62b5345d23a5912f03 100644
--- a/targets/RT/USER/rrh_gw.h
+++ b/targets/RT/USER/rrh_gw.h
@@ -45,41 +45,68 @@
 #include "vcd_signal_dumper.h"
 #include "assertions.h"
 
-#define DEFAULT_PERIOD_NS 200000
+#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 a device of type ETH_IF 
-	 and optionally with an RF device (USRP/BLADERF/EXMIMO) */
+	   each module is associated with an ethernet device (device of ETH_IF) 
+	   and optionally with a RF device (device type can be USRP_IF/BLADERF_IF/EXMIMO_IF/NONE_IF)
+           UE modules will always have RF device type NONE_IF */
 typedef struct {
-  //! module id
+/*! \brief module id */
   uint8_t id;
-  //! loopback flag
-  uint8_t loopback;
-  //! measurement flag
-  uint8_t measurements;
-  //! module's ethernet device
-  openair0_device eth_dev;
-  //! pointer to RF module's device (pointer->since its optional)
-  openair0_device *devs;
-  
+/*! \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;
 
-
-/******************************************************************************
- **                               FUNCTION PROTOTYPES                        **
- ******************************************************************************/
-void signal_handler(int sig);
+/*! \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 *);
-void create_timer_thread(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);
 
-/******************************************************************************
- **                               FUNCTION PROTOTYPES                        **
- ******************************************************************************/
-void create_UE_trx_threads( rrh_module_t *dev_ue, uint8_t RT_flag, uint8_t NRT_flag);
-void create_eNB_trx_threads( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag);
+
+
+void signal_handler(int sig);
 
 #endif