diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 46fd189952e8b975a3526761aaabb0d70eb8ba94..00ed6170f055959b13997757f7d1626c10e9e615 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -138,7 +138,7 @@ else (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
       set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mavx2")
     endif()
     if (CPUINFO MATCHES "sse4_1")
-      set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1 -mavx2")
+      set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1")
     endif()
     if (CPUINFO MATCHES "ssse3")
       set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mssse3")
@@ -960,6 +960,7 @@ add_boolean_option(OAI_NW_DRIVER_USE_NETLINK True "????")
 	  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/rar_tools.c
 	  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/print_stats.c
 	  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/initial_sync.c
+      ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if4_tools.c
 	  ${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c
 	  ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c
 	  ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_mbsfn.c
diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c
index cf41812c19def5640834d24ab142c1002763567c..15e98c36f6326405baa005342c783cbdec1fce46 100644
--- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c
@@ -29,7 +29,7 @@
 
 /*! \file PHY/LTE_TRANSPORT/if4_tools.c
 * \brief 
-* \author Mauricio Gunther, S. Sandeep Kumar, Raymond Knopp
+* \author Fredrik Skretteberg, Tobias Schuster, Mauricio Gunther, S. Sandeep Kumar, Raymond Knopp
 * \date 2016
 * \version 0.1
 * \company Eurecom
@@ -38,109 +38,137 @@
 * \warning
 */
 
-#ifndef USER_MODE
-#include "if4_tools.h"
 #include <stdint.h>
-#else
+
+#include "PHY/defs.h"
 #include "PHY/LTE_TRANSPORT/if4_tools.h"
-#endif
+#include "PHY/TOOLS/ALAW/alaw_lut.h"
 
 // Get device information
-void send_IF4(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc) {
-	int frame = proc->frame_tx;
-	int subframe = proc->subframe_tx;
-	LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
-	
-	uint16_t i;
-
-  float_t data_block_length = 1200*(fp->ofdm_symbol_size/2048);
-  uint16_t *data_block = (uint16_t*)malloc(data_block_length*sizeof(uint16_t));
+void send_IF4(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint16_t packet_type) {
+  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
+  int32_t **txdataF = eNB->common_vars.txdataF[0];
+  
+  uint16_t symbol_id, element_id;
+  uint16_t db_fulllength = 12*fp->N_RB_DL;
+  uint16_t db_halflength = db_fulllength>>1;
+  int slotoffsetF = (proc->subframe_tx)*(fp->ofdm_symbol_size)*((fp->Ncp==1) ? 12 : 14) + 1;
+  int blockoffsetF = slotoffsetF + fp->ofdm_symbol_size - db_halflength; 
+  
+  int16_t *data_block = (int16_t*)malloc(db_fulllength*sizeof(int16_t));  
 
   // Caller: RCC - DL *** handle RRU case - UL and PRACH *** 
-  if (eNB->node_function == NGFI_RCC_IF4) {
+  if (packet_type == IF4_PDLFFT) {
     IF4_dl_packet_t *dl_packet = (IF4_dl_packet_t*)malloc(sizeof_IF4_dl_packet_t);
     gen_IF4_dl_packet(dl_packet, proc);
 		
     dl_packet->data_block = data_block;
 
-    for(i=0; i<fp->symbols_per_tti; i++) {
-			
-      //Do compression of the two parts and generate data blocks
+    for (symbol_id=0; symbol_id<fp->symbols_per_tti; symbol_id++) {
+      
+      printf("\n Send IF4 for frame %d, subframe %d and symbol %d\n", proc->frame_tx, proc->subframe_tx, symbol_id);
 
-      //symbol = eNB->common_vars.txdataF[0][0 /*antenna number*/][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)]
-      //data_block[j] = Atan(symbol[fp->ofmd_symbol_size - NrOfNonZeroValues + j -1])<<16 + Atan(symbol[fp->ofmd_symbol_size - NrOfNonZeroValues + j]);
-      //data_block[j+NrOfNonZeroValues] = Atan(subframe[i][j+1])<<16 + Atan(subframe[i][j+2]);
-	 		
+      // Do compression of the two parts and generate data blocks			
+      for (element_id=0; element_id<db_halflength; element_id++) {
+        data_block[element_id]  = lin2alaw[ (txdataF[0][blockoffsetF+element_id] & 0xffff) + 32768 ];          
+        data_block[element_id] |= lin2alaw[ (txdataF[0][blockoffsetF+element_id]>>16) + 32768 ]<<8;  
+        
+        data_block[element_id+db_halflength]  = lin2alaw[ (txdataF[0][slotoffsetF+element_id] & 0xffff) + 32768 ];     
+        data_block[element_id+db_halflength] |= lin2alaw[ (txdataF[0][slotoffsetF+element_id]>>16) + 32768 ]<<8;  
+      }
+				 		
       // Update information in generated packet
-      dl_packet->frame_status.sym_num = i; 
+      dl_packet->frame_status.sym_num = symbol_id; 
 			
       // Write the packet(s) to the fronthaul
-      //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("RCC : ETHERNET write");
-      //}    
+    //  if ((bytes_sent = eNB->ifdevice.trx_write_func(&eNB->ifdevice,
+    //                                                (proc->timestamp_tx-eNB->ifdevice.openair0_cfg.tx_sample_advance),
+    //  			                                         dl_packet,
+    //  			                                         eNB->frame_parms.samples_per_tti,
+    //  			                                         eNB->frame_parms.nb_antennas_tx,
+    //                                                 0)) < 0) {
+    //    perror("RCC : ETHERNET write");
+    //}
+      
+      slotoffsetF  += fp->ofdm_symbol_size;
+      blockoffsetF += fp->ofdm_symbol_size;    
     }
-  }else {
+  } else if (packet_type == IF4_PULFFT) {
     IF4_ul_packet_t *ul_packet = (IF4_ul_packet_t*)malloc(sizeof_IF4_ul_packet_t);
     gen_IF4_ul_packet(ul_packet, proc);
 		
     ul_packet->data_block = data_block;
 
-    for(i=0; i<fp->symbols_per_tti; i++) {
-			
-      //Do compression of the two parts and generate data blocks
+    for (symbol_id=0; symbol_id<fp->symbols_per_tti; symbol_id++) {			
 
-      //symbol = eNB->common_vars.txdataF[0][0 /*antenna number*/][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)]
-      //data_block[j] = Atan(symbol[fp->ofmd_symbol_size - NrOfNonZeroValues + j -1])<<16 + Atan(symbol[fp->ofmd_symbol_size - NrOfNonZeroValues + j]);
-      //data_block[j+NrOfNonZeroValues] = Atan(subframe[i][j+1])<<16 + Atan(subframe[i][j+2]);
-			
+      // Do compression of the two parts and generate data blocks - rxdataF		
+      for (element_id=0; element_id<db_halflength; element_id++) {
+        //data_block[element_id]  = lin2alaw[ (rxdataF[0][blockoffsetF+element_id] & 0xffff) + 32768 ];          
+        //data_block[element_id] |= lin2alaw[ (rxdataF[0][blockoffsetF+element_id]>>16) + 32768 ]<<8;  
+        
+        //data_block[element_id+db_halflength]  = lin2alaw[ (txdataF[0][slotoffsetF+element_id] & 0xffff) + 32768 ];     
+        //data_block[element_id+db_halflength] |= lin2alaw[ (txdataF[0][slotoffsetF+element_id]>>16) + 32768 ]<<8;  
+      }
+       			
       // Update information in generated packet
-      ul_packet->frame_status.sym_num = i; 
+      ul_packet->frame_status.sym_num = symbol_id; 
 			
       // Write the packet(s) to the fronthaul 
 
+      slotoffsetF  += fp->ofdm_symbol_size;
+      blockoffsetF += fp->ofdm_symbol_size;    
     }		
-	}
-  		    
+  } else if (packet_type == IF4_PRACH) {
+       
+       
+  } else {    
+    AssertFatal(1==0, "send_IF4 - Unknown packet_type %x", packet_type);     
+  }
+  
+  return;  		    
 }
 
-void recv_IF4(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc) {
-
-  // Caller: RRU - DL *** handle RCC case - UL and PRACH *** 
-
-  if (eNB->node_function == NGFI_RRU_IF4) {
-  
+void recv_IF4(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint16_t *packet_type, uint32_t *symbol_number) {
+
+  *packet_type = 0;
+  int16_t *data_block=NULL;
+   
+  // Read packet(s) from the fronthaul    
+//    for(i=0; i<fp->symbols_per_tti; i++) {  
+//      if (dev->eth_dev.trx_read_func (&dev->eth_dev,
+//                                      timestamp_rx,
+//                                    rx_eNB,
+//                                      spp_eth,
+//                                      dev->eth_dev.openair0_cfg->rx_num_channels
+//                                      ) < 0) {
+//        perror("RRU : ETHERNET read");
+//      }
+//  printf("\n Recv IF4 for frame %d, subframe %d and symbol %d\n", proc->frame_tx, proc->subframe_tx, symbol_id);
+
+  //*packet_type = ;  
   
-  
-    for(i=0; i<fp->symbols_per_tti; i++) {  
-      // Read packet(s) from the fronthaul    
-      if (dev->eth_dev.trx_read_func (&dev->eth_dev,
-                                      timestamp_rx,
-                                      rx_eNB,
-                                      spp_eth,
-                                      dev->eth_dev.openair0_cfg->rx_num_channels
-                                      ) < 0) {
-        perror("RRU : ETHERNET read");
-      }
+  if (*packet_type == IF4_PDLFFT) {
       
       // Apply reverse processing - decompression
       // txAlawtolinear( Datablock )
       
       // Generate and return the OFDM symbols (txdataF)
-      txDataF 
-    }
-  }else {
+      // txDataF 
     
-  }  
+  } else if (*packet_type == IF4_PULFFT) {
+    
+  } else if (*packet_type == IF4_PRACH) {
+       
+  } else {
+    AssertFatal(1==0, "recv_IF4 - Unknown packet_type %x", *packet_type);            
+  }
+
+  return;   
 }
 
 void gen_IF4_dl_packet(IF4_dl_packet_t *dl_packet, eNB_rxtx_proc_t *proc) {      
   // Set Type and Sub-Type
-  dl_packet->type = 0x080A; 
+  dl_packet->type = IF4_PACKET_TYPE; 
   dl_packet->sub_type = IF4_PDLFFT;
 
   // Leave reserved as it is 
@@ -160,7 +188,7 @@ void gen_IF4_dl_packet(IF4_dl_packet_t *dl_packet, eNB_rxtx_proc_t *proc) {
 
 void gen_IF4_ul_packet(IF4_ul_packet_t *ul_packet, eNB_rxtx_proc_t *proc) {  
   // Set Type and Sub-Type
-  ul_packet->type = 0x080A; 
+  ul_packet->type = IF4_PACKET_TYPE; 
   ul_packet->sub_type = IF4_PULFFT;
 
   // Leave reserved as it is 
@@ -184,7 +212,7 @@ void gen_IF4_ul_packet(IF4_ul_packet_t *ul_packet, eNB_rxtx_proc_t *proc) {
 
 void gen_IF4_prach_packet(IF4_prach_packet_t *prach_packet, eNB_rxtx_proc_t *proc) {
   // Set Type and Sub-Type
-  prach_packet->type = 0x080A; 
+  prach_packet->type = IF4_PACKET_TYPE; 
   prach_packet->sub_type = IF4_PRACH;
 
   // Leave reserved as it is 
diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.h b/openair1/PHY/LTE_TRANSPORT/if4_tools.h
index 91a9e93d7900bdf4f8f6b276355064d72b0594b0..a6ca7eb5c015fbbdfcf306d224534d24f9b07056 100644
--- a/openair1/PHY/LTE_TRANSPORT/if4_tools.h
+++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.h
@@ -38,6 +38,10 @@
 * \warning
 */
 
+#include <stdint.h>
+
+/// Macro for IF4 packet type
+#define IF4_PACKET_TYPE 0x080A 
 #define IF4_PULFFT 0x0019 
 #define IF4_PDLFFT 0x0020
 #define IF4_PRACH 0x0021
@@ -103,7 +107,7 @@ struct IF4_dl_packet {
   /// Frame Status
   IF4_frame_status_t frame_status;
   /// Data Blocks
-  uint16_t *data_block;
+  int16_t *data_block;
   /// Frame Check Sequence
   uint32_t fcs; 
 };
@@ -141,7 +145,7 @@ struct IF4_ul_packet {
   /// Gain 7
   IF4_gain_t gain7;
   /// Data Blocks
-  uint16_t *data_block;
+  int16_t *data_block;
   /// Frame Check Sequence
   uint32_t fcs;
 };
@@ -163,7 +167,7 @@ struct IF4_prach_packet {
   /// LTE Prach Configuration
   IF4_lte_prach_conf_t prach_conf;
   /// Prach Data Block (one antenna)
-  uint16_t *data_block;
+  int16_t *data_block;
   /// Frame Check Sequence
   uint32_t fcs;
 };
@@ -177,6 +181,6 @@ void gen_IF4_ul_packet(IF4_ul_packet_t*, eNB_rxtx_proc_t*);
 
 void gen_IF4_prach_packet(IF4_prach_packet_t*, eNB_rxtx_proc_t*);
 
-void send_IF4(PHY_VARS_eNB*, eNB_rxtx_proc_t*);
+void send_IF4(PHY_VARS_eNB*, eNB_rxtx_proc_t*, uint16_t);
 
-void recv_IF4(PHY_VARS_eNB*, eNB_rxtx_proc_t*, int*, int*);
+void recv_IF4(PHY_VARS_eNB*, eNB_rxtx_proc_t*, uint16_t*, uint32_t*);
diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c
index 0f806e2ea1e7bd38fed9619f9db1d9f1c0d40e69..85330b5a18193c97f0e6edb2276674371b83340f 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach.c
@@ -1269,16 +1269,19 @@ void rx_prach(PHY_VARS_eNB *eNB,
   }
 
   if (eNB->node_function == NGFI_RRU_IF4) {
-    //send prachF to RCC
+    /// **** send_IF4 of prachF to RCC **** ///    
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 1 );   
+    // send_IF4();
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 0 );   
+
     return;
   }
+  
   // in case of RCC and prach received rx_thread wakes up prach
   //else if (eNB->node_function == NGFI_RCC_IF4) {
-    //wait for prachF from RRU and continue with PRACH processing
+  //  wait for prachF from RRU and continue with PRACH processing
   //}
 
-
-
   // here onwards is for eNodeB_3GPP or NGFI_RCC_IF4
 
   preamble_offset_old = 99;
diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index 89fc1cd7ed39dfaf89ffdc8c9c69d37ba813b24c..ed3ca5c2512147cb933094a32d1afbcbb827dba0 100755
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -139,6 +139,8 @@ static inline void* malloc16_clear( size_t size )
 #include "PHY/LTE_TRANSPORT/defs.h"
 #include <pthread.h>
 
+#include "targets/ARCH/COMMON/common_lib.h"
+
 #define NUM_DCI_MAX 32
 
 #define NUMBER_OF_eNB_SECTORS_MAX 3
@@ -456,6 +458,11 @@ typedef struct PHY_VARS_eNB_s {
   SLIST_HEAD(ral_thresholds_gen_poll_enb_s, ral_threshold_phy_t) ral_thresholds_gen_polled[RAL_LINK_PARAM_GEN_MAX];
   SLIST_HEAD(ral_thresholds_lte_poll_enb_s, ral_threshold_phy_t) ral_thresholds_lte_polled[RAL_LINK_PARAM_LTE_MAX];
 #endif
+  
+  /// RF and Interface devices per CC
+  openair0_device rfdevice; 
+  openair0_device ifdevice;
+  // *** Handle spatially distributed MIMO antenna ports   
 
 } PHY_VARS_eNB;
 
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 0e1685d266253d2f3331e3e623118cf341abd22c..92392070af3b4c3002fb99ee9210281ffc87cb1f 100755
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -44,6 +44,8 @@
 #include "SCHED/defs.h"
 #include "SCHED/extern.h"
 
+#include "PHY/LTE_TRANSPORT/if4_tools.h"
+
 #ifdef EMOS
 #include "SCHED/phy_procedures_emos.h"
 #endif
@@ -59,6 +61,8 @@
 #include "assertions.h"
 #include "msc.h"
 
+#include <time.h>
+
 #if defined(ENABLE_ITTI)
 #   include "intertask_interface.h"
 #endif
@@ -73,7 +77,8 @@ void exit_fun(const char* s);
 
 extern int exit_openair;
 
-extern openair0_device openair0;
+// Fix per CC openair rf/if device update
+// extern openair0_device openair0;
 
 unsigned char dlsch_input_buffer[2700] __attribute__ ((aligned(32)));
 int eNB_sync_buffer0[640*6] __attribute__ ((aligned(32)));
@@ -1429,24 +1434,6 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
 
 #endif
 
-  // Clean up split point *** RRU only function to recv and do_OFDM_mod ***  
-  if (eNB->node_function == eNodeB_3GPP) {
-    // Add above to IF4 split
-    // do_OFDM_mod
-    
-  }else if (eNB->node_function == NGFI_RCC_IF4) {
-	  //send_IF4(eNB,subframe<<1);
-	  //send_IF4(eNB,(subframe<<1)+1);
-    
-  }else if (eNB->node_function == NGFI_RRU_IF4) { // => acquisition from RCC (IF4)
-  	// get frame/subframe information from IF4 interface
-
-	  //recv_IF4(eNB,subframe<<1);
-	  //recv_IF4(eNB,1+(subframe<<1));
-    
-    //do_OFDM_mod   
-  }
-  
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX,0);
   stop_meas(&eNB->phy_proc_tx);
   
@@ -2488,7 +2475,6 @@ void cba_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_p
 }
 
 
-
 void phy_procedures_eNB_common_RX(PHY_VARS_eNB *eNB,const uint8_t abstraction_flag) {
 
   int i,l;
@@ -2498,160 +2484,198 @@ void phy_procedures_eNB_common_RX(PHY_VARS_eNB *eNB,const uint8_t abstraction_fl
   eNB_proc_t *proc = &eNB->proc;
   int subframe = proc->subframe_rx;
   int frame = proc->frame_rx;
-  int symbol_number, symbol_mask, symbol_mask_full, prach_rx, packet_type;
 
+  int prach_rx;
+
+  uint16_t packet_type;
+  uint32_t symbol_number;
+  uint32_t symbol_mask, symbol_mask_full;
+  
+  struct timespec time_req, time_rem;  
+  time_req.tv_sec = 0;
+  time_req.tv_nsec = 300000;
+  
   if (subframe==9) { 
     subframe=0;
     frame++;
     frame&=1023;
+  } else {
+		subframe++;
   }
-  else subframe++;
-
+  
   //  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_COMMON_RX,1);
   start_meas(&eNB->phy_proc_rx);
+
 #ifdef DEBUG_PHY_PROC
   LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_RX(%d)\n",eNB->Mod_id,frame, subframe);
 #endif
 
   if (abstraction_flag==0) { // grab signal in chunks of 500 us (1 slot)
-    
-
-      if ((eNB->node_function == NGFI_RRU_IF4) || 
-	  (eNB->node_function == eNodeB_3GPP)) { // acquisition from RF and front-end processing
-	for (i=0; i<fp->nb_antennas_rx; i++)
-	  rxp[i] = (void*)&eNB->common_vars.rxdata[0][i][subframe*fp->samples_per_tti];
-
-	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
-	rxs = openair0.trx_read_func(&openair0,
-				     &proc->timestamp_rx,
-				     rxp,
-				     fp->samples_per_tti,
-				     fp->nb_antennas_rx);
-	proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
-	proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
-	if (proc->first_rx == 0) {
-	  AssertFatal(proc->subframe_rx == subframe, "Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)",proc->subframe_rx,subframe);
-	  AssertFatal(proc->frame_rx == frame, "Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)",proc->frame_rx,frame);
-	}
-	else
-	  proc->first_rx = 0;
-
-	//	printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",proc->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe);
+		
+    if ((eNB->node_function == NGFI_RRU_IF4) || 
+	      (eNB->node_function == eNodeB_3GPP)) { // acquisition from RF and front-end processing
+
+	    for (i=0; i<fp->nb_antennas_rx; i++)
+	      rxp[i] = (void*)&eNB->common_vars.rxdata[0][i][subframe*fp->samples_per_tti];
+
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
+      rxs = eNB->rfdevice.trx_read_func(&eNB->rfdevice,
+			  	                              &proc->timestamp_rx,
+		  	 	                              rxp,
+				                                fp->samples_per_tti,
+				                                fp->nb_antennas_rx);
+      proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
+      proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
+
+      if (proc->first_rx == 0) {
+        AssertFatal(proc->subframe_rx == subframe, "Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)",proc->subframe_rx,subframe);
+        AssertFatal(proc->frame_rx == frame, "Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)",proc->frame_rx,frame);
+      } else {
+        proc->first_rx = 0;
+			}
 
-	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
-	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB, frame );
-	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_ENB, subframe );
+      //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",proc->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe);
 
+      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
+      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB, frame );
+      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_ENB, subframe );
 
-	if (rxs != fp->samples_per_tti)
-	  exit_fun( "problem receiving samples" );
+      if (rxs != fp->samples_per_tti)
+        exit_fun( "problem receiving samples" );
 	
-	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
-
-	// now do common RX processing for first slot in subframe
-	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,1);
-	remove_7_5_kHz(eNB,subframe<<1);
-	remove_7_5_kHz(eNB,1+(subframe<<1));
-	for (l=0; l<fp->symbols_per_tti/2; l++) {
-	  slot_fep_ul(fp,
-		      &eNB->common_vars,
-		      l,
-		      subframe<<1,
-		      0,
-		      0
-		      );
-	  slot_fep_ul(fp,
-		      &eNB->common_vars,
-		      l,
-		      1+(subframe<<1),
-		      0,
-		      0
-		      );
-	}
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
+
+      // now do common RX processing for first slot in subframe
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,1);
+      remove_7_5_kHz(eNB,subframe<<1);
+      remove_7_5_kHz(eNB,1+(subframe<<1));
+      for (l=0; l<fp->symbols_per_tti/2; l++) {
+        slot_fep_ul(fp,
+                    &eNB->common_vars,
+                    l,
+                    subframe<<1,
+                    0,
+                    0
+                    );
+        slot_fep_ul(fp,
+                    &eNB->common_vars,
+                    l,
+                    1+(subframe<<1),
+                    0,
+                    0
+                    );
+      }
     	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,0);
 
-	if (eNB->node_function == NGFI_RRU_IF4) {
-	  //send_IF4(eNB,subframe<<1);
-	  //send_IF4(eNB,(subframe<<1)+1);
-	}
+      if (eNB->node_function == NGFI_RRU_IF4 && is_prach_subframe(fp, frame, subframe)<=0) {
 
+			  /// **** send_IF4 of rxdataF to RCC (no prach now) **** ///
+        
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 1 );   
+        // send_IF4();
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 0 );   
+        
       }
-      else if (eNB->node_function == NGFI_RCC_IF4) { // => acquisition from RRU (IF4)
-	      // get frame/subframe information from IF4 interface
-	      // timed loop (200 us)
-	
-        //symbol_mask = 0;
-        //symbol_mask_full = (1<<fp->symbols_per_tti)-1;
-        //if (is_prach_subframe(fp,frame,subframe)>0)
-          //prach_rx = 0;
-        //else
-          //prach_rx = 1;
-          
-        //do {
-				  //recv_IF4(eNB, proc, &packet_type, &symbol_number);
-				  //if (is_prach_subframe(fp,frame,subframe)>0 && packet_type == PRACH) {
-					  //// wake up prach_rx
-					  //prach_rx = 1;
-					//}
-					//if (packet_type == IF4_PULFFT)
-					  //symbol_mask = symbol_mask | (1<<symbol_number);
-					
-				//} while( (symbol_mask != symbol_mask_full) || (prach_rx == 0));    
-					 
-
-	      //recv_IF4(eNB,subframe<<1);
-	      //recv_IF4(eNB,1+(subframe<<1));
-	
-	    // Tobi aka mr monaco: ETH
-	
-	    
-      }
-      else { // should not get here
-	AssertFatal(1==0, "Unknown eNB->node_function %d",eNB->node_function);
-      }
- 
-  
-    // check if we have to detect PRACH first
-    if (is_prach_subframe(fp,frame,subframe)>0) {
-      // wake up thread for PRACH RX
-      if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
-	LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->instance_cnt_prach );
-	exit_fun( "error locking mutex_prach" );
-	return;
-      }
-      
-      int cnt_prach = ++proc->instance_cnt_prach;
-      // set timing for prach thread
-      proc->frame_prach = frame;
-      proc->subframe_prach = subframe;
 
-      pthread_mutex_unlock( &proc->mutex_prach );
-      
-      if (cnt_prach == 0) {
-	// the thread was presumably waiting where it should and can now be woken up
-	if (pthread_cond_signal(&proc->cond_prach) != 0) {
-	  LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index);
-	  exit_fun( "ERROR pthread_cond_signal" );
-	  return;
-	}
-      } else {
-	LOG_W( PHY,"[eNB] Frame %d, eNB PRACH thread busy!!\n", frame);
-	exit_fun( "PRACH thread busy" );
-	return;
+      /// **** send_IF4 of prach to RCC **** /// done in prach thread (below)
+      // check if we have to detect PRACH first
+      if (is_prach_subframe(fp,frame,subframe)>0) {
+        // wake up thread for PRACH RX
+        if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
+          LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->instance_cnt_prach );
+          exit_fun( "error locking mutex_prach" );
+          return;
+		    }
+		
+        int cnt_prach = ++proc->instance_cnt_prach;
+        // set timing for prach thread
+        proc->frame_prach = frame;
+        proc->subframe_prach = subframe;
+
+        pthread_mutex_unlock( &proc->mutex_prach );
+		
+        if (cnt_prach == 0) {
+          // the thread was presumably waiting where it should and can now be woken up
+          if (pthread_cond_signal(&proc->cond_prach) != 0) {
+            LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index);
+            exit_fun( "ERROR pthread_cond_signal" );
+            return;
+          }
+        } else {
+          LOG_W( PHY,"[eNB] Frame %d, eNB PRACH thread busy!!\n", frame);
+          exit_fun( "PRACH thread busy" );
+          return;
+        }
       }
+    
+    } else if (eNB->node_function == NGFI_RCC_IF4) {
+      /// **** recv_IF4 of rxdataF from RRU **** ///
+      /// **** recv_IF4 of prachF from RRU **** ///
+      // get frame/subframe information from IF4 interface
+      // timed loop (200 us)
+
+      symbol_mask = 0;
+      symbol_mask_full = (1<<fp->symbols_per_tti)-1;
+      prach_rx = 0;
+
+      // Block from loop while testing
+      symbol_mask = symbol_mask_full;
+      nanosleep(&time_req, &time_rem);
+         
+      do {
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 1 );   
+        //recv_IF4(eNB, proc, &packet_type, &symbol_number);
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 0 );   
+
+        if (packet_type == IF4_PULFFT) {
+          symbol_mask = symbol_mask | (1<<symbol_number);     
+                       
+        } else if (is_prach_subframe(fp,frame,subframe)>0 && packet_type == PRACH) {
+          // wake up thread for PRACH RX
+          prach_rx = 1;
+
+          if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
+            LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->instance_cnt_prach );
+            exit_fun( "error locking mutex_prach" );
+            return;
+		      }
+		
+          int cnt_prach = ++proc->instance_cnt_prach;
+          // set timing for prach thread
+          proc->frame_prach = frame;
+          proc->subframe_prach = subframe;
+
+          pthread_mutex_unlock( &proc->mutex_prach );
+		
+          if (cnt_prach == 0) {
+            // the thread was presumably waiting where it should and can now be woken up
+            if (pthread_cond_signal(&proc->cond_prach) != 0) {
+              LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index);
+              exit_fun( "ERROR pthread_cond_signal" );
+              return;
+            }
+          } else {
+            LOG_W( PHY,"[eNB] Frame %d, eNB PRACH thread busy!!\n", frame);
+            exit_fun( "PRACH thread busy" );
+            return;
+          }
+        }
 
+      } while( (symbol_mask != symbol_mask_full) && (prach_rx == 0));    
 
+      // Tobi aka mr monaco: ETH
+		  
+    } else { // should not get here
+      AssertFatal(1==0, "Unknown eNB->node_function %d",eNB->node_function);
     }
-    
-
-    
-  }
 
-  else {  // grab transport channel information from network interface
+  } else { // grab transport channel information from network interface
 
   }
+
 }
 
+
 void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const uint8_t abstraction_flag,const relaying_type_t r_type)
 {
   //RX processing for ue-specific resources (i
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c
index 3f8ddd89ef42a2226d3ef52c0a30d30fa4d28e75..73abd5d698827e043da05c466c0dc94098ec5b19 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.c
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.c
@@ -329,7 +329,11 @@ const char* eurecomFunctionsNames[] = {
   "itti_dump_enqueue_message",
   "itti_dump_enqueue_message_malloc",
   "itti_relay_thread",
-  "test"
+  "test",
+  
+  /* IF4 signals */
+  "send_if4",
+  "recv_if4"
 };
 
 struct vcd_module_s vcd_modules[VCD_SIGNAL_DUMPER_MODULE_END] = {
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h
index 11401f17af7534412c48eb18e1992e661b259656..25df492abe7bb1f2ac2670164c21f9720d10ba36 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.h
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.h
@@ -307,6 +307,11 @@ typedef enum {
   VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC,
   VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_RELAY_THREAD,
   VCD_SIGNAL_DUMPER_FUNCTIONS_TEST,
+  
+  /* IF4 signals */
+  VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4,
+  VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4,
+  
   VCD_SIGNAL_DUMPER_FUNCTIONS_LAST,
   VCD_SIGNAL_DUMPER_FUNCTIONS_END = VCD_SIGNAL_DUMPER_FUNCTIONS_LAST,
 } vcd_signal_dump_functions;
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index f59ec9ba646fc5481262225278b8013beeb872d1..0113ee4b5bf5716978113f7b0e35b287193cd488 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -68,6 +68,8 @@
 
 //#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
 
+#include "PHY/LTE_TRANSPORT/if4_tools.h"
+
 #include "PHY/extern.h"
 #include "SCHED/extern.h"
 #include "LAYER2/MAC/extern.h"
@@ -106,10 +108,6 @@ unsigned short config_frames[4] = {2,9,11,13};
 # endif
 #endif
 
-
-
-
-
 //#define DEBUG_THREADS 1
 
 //#define USRP_DEBUG 1
@@ -120,8 +118,8 @@ struct timing_info_t {
   unsigned int n_samples;
 } timing_info;
 
-
-extern openair0_device openair0;
+// Fix per CC openair rf/if device update
+// extern openair0_device openair0;
 
 #if defined(ENABLE_ITTI)
 extern volatile int             start_eNB;
@@ -156,15 +154,14 @@ static struct {
   volatile uint8_t phy_proc_CC_id;
 } sync_phy_proc;
 
-
 void exit_fun(const char* s);
 
 void init_eNB(eNB_func_t node_function);
 void stop_eNB(void);
 
-void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
-{
 
+void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) {
+     
   unsigned int aa,slot_offset, slot_offset_F;
   int dummy_tx_b[7680*4] __attribute__((aligned(32)));
   int i,j, tx_offset;
@@ -181,7 +178,6 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
       ((subframe_select(&phy_vars_eNB->frame_parms,subframe)==SF_S))) {
     //    LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);
 
-
     for (aa=0; aa<phy_vars_eNB->frame_parms.nb_antennas_tx; aa++) {
       if (phy_vars_eNB->frame_parms.Ncp == EXTENDED) {
         PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F],
@@ -202,7 +198,7 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
                           7,
                           &(phy_vars_eNB->frame_parms));
 	// if S-subframe generate first slot only
-	if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL)
+	if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) 
 	  normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
 			    dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1),
 			    7,
@@ -235,9 +231,8 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
 	    txdata[j++] = ((int16_t*)dummy_tx_b)[i]<<openair0_cfg[0].iq_txshift;
 	  }
 	}
-      }
+      }  
       else if ((slot_offset+time_offset[aa]+len)>(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti)) {
-
 	tx_offset = (int)slot_offset+time_offset[aa];
 	txdata = (int16_t*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset];
 	len2 = -tx_offset+LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
@@ -258,7 +253,6 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
 	}
       }
       
-
      // if S-subframe switch to RX in second subframe
       /*
      if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_S) {
@@ -268,34 +262,35 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
      }
       */
      if ((((phy_vars_eNB->frame_parms.tdd_config==0) ||
-	  (phy_vars_eNB->frame_parms.tdd_config==1) ||
-	  (phy_vars_eNB->frame_parms.tdd_config==2) ||
-	  (phy_vars_eNB->frame_parms.tdd_config==6)) && 
-	  (subframe==0)) || (subframe==5)) {
+	   (phy_vars_eNB->frame_parms.tdd_config==1) ||
+	   (phy_vars_eNB->frame_parms.tdd_config==2) ||
+	   (phy_vars_eNB->frame_parms.tdd_config==6)) && 
+	   (subframe==0)) || (subframe==5)) {
        // turn on tx switch N_TA_offset before
        //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset);
        for (i=0; i<phy_vars_eNB->N_TA_offset; i++) {
-	 tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2;
-	 if (tx_offset<0)
-	   tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
+         tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2;
+         if (tx_offset<0)
+           tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
 	 
-	 if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti))
-	   tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
+         if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti))
+           tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
 	 
-	 phy_vars_eNB->common_vars.txdata[0][aa][tx_offset] = 0x00000000;
+         phy_vars_eNB->common_vars.txdata[0][aa][tx_offset] = 0x00000000;
        }
      }
     }
   }
 }
 
+
 /*!
  * \brief The RX UE-specific and TX thread of eNB.
  * \param param is a \ref eNB_proc_t structure which contains the info what to process.
  * \returns a pointer to an int. The storage is not on the heap and must not be freed.
  */
-static void* eNB_thread_rxtx( void* param )
-{
+static void* eNB_thread_rxtx( void* param ) {
+
   static int eNB_thread_rxtx_status;
 
   eNB_rxtx_proc_t *proc = (eNB_rxtx_proc_t*)param;
@@ -364,56 +359,47 @@ static void* eNB_thread_rxtx( void* param )
 #endif //CPU_AFFINITY
 
   /* Check the actual affinity mask assigned to the thread */
-
   s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-  if (s != 0)
-  {
+  if (s != 0) {
     perror( "pthread_getaffinity_np");
     exit_fun("Error getting processor affinity ");
   }
   memset(cpu_affinity,0,sizeof(cpu_affinity));
   for (j = 0; j < CPU_SETSIZE; j++)
-     if (CPU_ISSET(j, &cpuset))
-     {  
-        char temp[1024];
-        sprintf (temp, " CPU_%d", j);
-        strcat(cpu_affinity, temp);
-     }
+    if (CPU_ISSET(j, &cpuset)) {  
+      char temp[1024];
+      sprintf (temp, " CPU_%d", j);
+      strcat(cpu_affinity, temp);
+    }
 
-  memset(&sparam, 0 , sizeof (sparam));
+  memset(&sparam, 0, sizeof(sparam));
   sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
   policy = SCHED_FIFO ; 
   
   s = pthread_setschedparam(pthread_self(), policy, &sparam);
-  if (s != 0)
-     {
-     perror("pthread_setschedparam : ");
-     exit_fun("Error setting thread priority");
-     }
+  if (s != 0) {
+    perror("pthread_setschedparam : ");
+    exit_fun("Error setting thread priority");
+  }
+  
   s = pthread_getschedparam(pthread_self(), &policy, &sparam);
-  if (s != 0)
-   {
-     perror("pthread_getschedparam : ");
-     exit_fun("Error getting thread priority");
-
-   }
+  if (s != 0) {
+    perror("pthread_getschedparam : ");
+    exit_fun("Error getting thread priority");
+  }
 
- LOG_I( HW, "[SCHED][eNB] TX thread started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",sched_getcpu(),gettid(),
+  LOG_I(HW, "[SCHED][eNB] TX thread started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",sched_getcpu(),gettid(),
                    (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
                    (policy == SCHED_RR)    ? "SCHED_RR" :
                    (policy == SCHED_OTHER) ? "SCHED_OTHER" :
                    "???",
                    sparam.sched_priority, cpu_affinity );
 
-
 #endif //LOW_LATENCY
 
-
   mlockall(MCL_CURRENT | MCL_FUTURE);
 
-
   while (!oai_exit) {
-
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
 
     if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
@@ -461,6 +447,7 @@ static void* eNB_thread_rxtx( void* param )
         exit_fun("nothing to add");
         break;
       }
+      
       // wait for our turn or oai_exit
       while (sync_phy_proc.phy_proc_CC_id != proc->CC_id && !oai_exit) {
         pthread_cond_wait(&sync_phy_proc.cond_phy_proc_tx,
@@ -472,72 +459,86 @@ static void* eNB_thread_rxtx( void* param )
         exit_fun("nothing to add");
       }
 
-      
-
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_ENB, proc->frame_tx );
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX_ENB, proc->subframe_tx );
-      if (oai_exit)
-        break;
+      
+      if (oai_exit) break;
+      
       if (PHY_vars_eNB_g[0][proc->CC_id]->node_function != NGFI_RRU_IF4) { 
-	phy_procedures_eNB_TX(PHY_vars_eNB_g[0][proc->CC_id], proc, 0, no_relay, NULL );
-	
-	/* we're done, let the next one proceed */
-	if (pthread_mutex_lock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
-	  LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc\n");
-	  exit_fun("nothing to add");
-	  break;
-	}
-	sync_phy_proc.phy_proc_CC_id++;
-	sync_phy_proc.phy_proc_CC_id %= MAX_NUM_CCs;
-	pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
-	if (pthread_mutex_unlock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
-	  LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc\n");
-	  exit_fun("nothing to add");
-	  break;
+        phy_procedures_eNB_TX(PHY_vars_eNB_g[0][proc->CC_id], proc, 0, no_relay, NULL );
+
+        /* we're done, let the next one proceed */
+        if (pthread_mutex_lock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
+          LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc\n");
+          exit_fun("nothing to add");
+          break;
+        }	
+        sync_phy_proc.phy_proc_CC_id++;
+        sync_phy_proc.phy_proc_CC_id %= MAX_NUM_CCs;
+        pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
+        if (pthread_mutex_unlock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
+          LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc\n");
+          exit_fun("nothing to add");
+          break;
 	}
+      } else {
+
+        /// **** recv_IF4 of txdataF from RCC **** ///     
+        
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 1 );   
+        //recv_IF4(eNB, proc, packet_type, symbol_number);        
+        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 0 );   
+        
       }
     }
 
+    // eNodeB_3GPP and RRU create txdata and write to RF device
     if (PHY_vars_eNB_g[0][proc->CC_id]->node_function != NGFI_RCC_IF4) {
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_SFGEN , 1 );
       do_OFDM_mod_rt( proc->subframe_tx, PHY_vars_eNB_g[0][proc->CC_id] );
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_SFGEN , 0 );
-    /*
-      short *txdata = (short*)&PHY_vars_eNB_g[0][proc->CC_id]->common_vars.txdata[0][0][proc->subframe_tx*PHY_vars_eNB_g[0][proc->CC_id]->frame_parms.samples_per_tti];
-      int i;
-      for (i=0;i<PHY_vars_eNB_g[0][proc->CC_id]->frame_parms.samples_per_tti*2;i+=8) {
-      txdata[i] = 2047;
-      txdata[i+1] = 0;
-      txdata[i+2] = 0;
-      txdata[i+3] = 2047;
-      txdata[i+4] = -2047;
-      txdata[i+5] = 0;
-      txdata[i+6] = 0;
-      txdata[i+7] = -2047;      }
-    */
-
+  
+      /*
+        short *txdata = (short*)&PHY_vars_eNB_g[0][proc->CC_id]->common_vars.txdata[0][0][proc->subframe_tx*PHY_vars_eNB_g[0][proc->CC_id]->frame_parms.samples_per_tti];
+        int i;
+        for (i=0;i<PHY_vars_eNB_g[0][proc->CC_id]->frame_parms.samples_per_tti*2;i+=8) {
+        txdata[i] = 2047;
+        txdata[i+1] = 0;
+        txdata[i+2] = 0;
+        txdata[i+3] = 2047;
+        txdata[i+4] = -2047;
+        txdata[i+5] = 0;
+        txdata[i+6] = 0;
+        txdata[i+7] = -2047;      }
+      */
 
-      // Transmit TX buffer based on timestamp from RX
-    
+      // Transmit TX buffer based on timestamp from RX  
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
       // prepare tx buffer pointers
       int i;
       for (i=0; i<PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx; i++)
-	txp[i] = (void*)&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][i][proc->subframe_tx*PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti];
+        txp[i] = (void*)&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][i][proc->subframe_tx*PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti];
+    
       // if symb_written < spp ==> error 
-      openair0.trx_write_func(&openair0,
-			      (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance),
-			      txp,
-			      PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti,
-			      PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx,
-			      1);
-      
-
-	
+      PHY_vars_eNB_g[0][proc->CC_id]->rfdevice.trx_write_func(&PHY_vars_eNB_g[0][proc->CC_id]->rfdevice,
+            (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance),
+            txp,
+            PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti,
+            PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx,
+            1);
+	      
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
-
+ 
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance)&0xffffffff );
 
+    } else { 
+	 
+      /// **** send_IF4 of txdataF to RRU **** /// 
+      
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 1 );   
+      //send_IF4(PHY_vars_eNB_g[0][proc->CC_id], proc, 0);
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 0 );
+
     }
 
     if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
@@ -555,19 +556,17 @@ static void* eNB_thread_rxtx( void* param )
     }
 
     stop_meas( &softmodem_stats_rxtx_sf );
+
 #ifdef DEADLINE_SCHEDULER
     if (opp_enabled){
       if(softmodem_stats_rxtx_sf.diff_now/(cpuf) > attr.sched_runtime){
 	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB, (softmodem_stats_rxtx_sf.diff_now/cpuf - attr.sched_runtime)/1000000.0);
-      }
     }
 #endif 
-    print_meas_now(&softmodem_stats_rxtx_sf,"eNB_TX_SF",tx_time_file);
 
+    print_meas_now(&softmodem_stats_rxtx_sf,"eNB_TX_SF",tx_time_file);
   }
 
-
-
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
 
 #ifdef DEBUG_THREADS
@@ -579,13 +578,11 @@ static void* eNB_thread_rxtx( void* param )
 }
 
 #if defined(ENABLE_ITTI)
-static void wait_system_ready (char *message, volatile int *start_flag)
-
-  /* Wait for eNB application initialization to be complete (eNB registration to MME) */
-{
+/* Wait for eNB application initialization to be complete (eNB registration to MME) */
+static void wait_system_ready (char *message, volatile int *start_flag) {
+  
   static char *indicator[] = {".    ", "..   ", "...  ", ".... ", ".....",
-			      " ....", "  ...", "   ..", "    .", "     "
-  };
+			      " ....", "  ...", "   ..", "    .", "     "};
   int i = 0;
   
   while ((!oai_exit) && (*start_flag == 0)) {
@@ -597,16 +594,16 @@ static void wait_system_ready (char *message, volatile int *start_flag)
   
   LOG_D(EMU,"\n");
 }
-
 #endif
 
+
 /*!
  * \brief The RX common thread of eNB.
  * \param param is a \ref eNB_proc_t structure which contains the info what to process.
  * \returns a pointer to an int. The storage is not on the heap and must not be freed.
  */
-static void* eNB_thread_rx_common( void* param )
-{
+static void* eNB_thread_rx_common( void* param ) {
+  
   static int eNB_thread_rx_status;
 
   eNB_proc_t *proc = (eNB_proc_t*)param;
@@ -617,7 +614,7 @@ static void* eNB_thread_rx_common( void* param )
   char rx_time_name[101];
   //int i;
 
-  if (opp_enabled == 1){
+  if (opp_enabled == 1) {
     snprintf(rx_time_name, 100,"/tmp/%s_rx_time_thread_sf", "eNB");
     rx_time_file = fopen(rx_time_name,"w");
   }
@@ -662,14 +659,12 @@ static void* eNB_thread_rx_common( void* param )
   /* Set CPU Affinity only if number of CPUs >2 */
   CPU_ZERO(&cpuset);
 #ifdef CPU_AFFINITY
-  if (get_nprocs() >2)
-  {
+  if (get_nprocs() >2) {
     for (j = 1; j < get_nprocs(); j++)
-       CPU_SET(j, &cpuset);
+      CPU_SET(j, &cpuset);
   
     s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-    if (s != 0)
-    {
+    if (s != 0) {
       perror( "pthread_setaffinity_np");  
       exit_fun (" Error setting processor affinity :");
     }
@@ -678,44 +673,38 @@ static void* eNB_thread_rx_common( void* param )
   /* Check the actual affinity mask assigned to the thread */
 
   s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-  if (s != 0)
-  {
-     perror ("pthread_getaffinity_np");
-     exit_fun (" Error getting processor affinity :");
+  if (s != 0) {
+    perror ("pthread_getaffinity_np");
+    exit_fun (" Error getting processor affinity :");
   }
   memset(cpu_affinity,0, sizeof(cpu_affinity));
 
   for (j = 0; j < CPU_SETSIZE; j++)
-     if (CPU_ISSET(j, &cpuset))
-     {  
-        char temp[1024];
-        sprintf (temp, " CPU_%d", j);
-        strcat(cpu_affinity, temp);
-     }
-
+    if (CPU_ISSET(j, &cpuset)) {  
+      char temp[1024];
+      sprintf (temp, " CPU_%d", j);
+      strcat(cpu_affinity, temp);
+    }
 
   memset(&sparam, 0 , sizeof (sparam)); 
   sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
 
   policy = SCHED_FIFO ; 
   s = pthread_setschedparam(pthread_self(), policy, &sparam);
-  if (s != 0)
-     {
-     perror("pthread_setschedparam : ");
-     exit_fun("Error setting thread priority");
-     }
+  if (s != 0) {
+    perror("pthread_setschedparam : ");
+    exit_fun("Error setting thread priority");     
+  }
 
   memset(&sparam, 0 , sizeof (sparam));
 
   s = pthread_getschedparam(pthread_self(), &policy, &sparam);
-  if (s != 0)
-   {
-     perror("pthread_getschedparam");
-     exit_fun("Error getting thread priority");
-   }
-
+  if (s != 0) {
+    perror("pthread_getschedparam");
+    exit_fun("Error getting thread priority");
+  }
 
-  LOG_I( HW, "[SCHED][eNB] RX thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),
+  LOG_I(HW, "[SCHED][eNB] RX thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),
 	 (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
 	 (policy == SCHED_RR)    ? "SCHED_RR" :
 	 (policy == SCHED_OTHER) ? "SCHED_OTHER" :
@@ -725,115 +714,122 @@ static void* eNB_thread_rx_common( void* param )
   
 #endif // DEADLINE_SCHEDULER
 
- mlockall(MCL_CURRENT | MCL_FUTURE);
 
+  mlockall(MCL_CURRENT | MCL_FUTURE);
 
- // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe of TX and RX threads
- printf( "waiting for sync (eNB_thread_rx_common)\n");
- pthread_mutex_lock( &sync_mutex );
+  // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe of TX and RX threads
+  printf( "waiting for sync (eNB_thread_rx_common)\n");
+  pthread_mutex_lock( &sync_mutex );
 
- while (sync_var<0)
-   pthread_cond_wait( &sync_cond, &sync_mutex );
+  while (sync_var<0)
+    pthread_cond_wait( &sync_cond, &sync_mutex );
  
- pthread_mutex_unlock(&sync_mutex);
+  pthread_mutex_unlock(&sync_mutex);
  
- printf( "got sync (eNB_thread)\n" );
+  printf( "got sync (eNB_thread)\n" );
  
 #if defined(ENABLE_ITTI)
   wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
 #endif 
-  if (openair0.trx_start_func(&openair0) != 0 ) 
-    LOG_E(HW,"Could not start the device\n");
- // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
- while (!oai_exit) {
-   
-   
-   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX, 0 );
-   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 0 );
-   start_meas( &softmodem_stats_rx_sf );
+  
+  // Start RF device for this CC
+  if (eNB->node_function != NGFI_RCC_IF4) {
+    if (eNB->rfdevice.trx_start_func(&eNB->rfdevice) != 0 ) 
+      LOG_E(HW,"Could not start the RF device\n");
+  }
+    
+  // Start IF device for this CC
+  if (eNB->node_function != eNodeB_3GPP) {
+    if (eNB->ifdevice.trx_start_func(&eNB->ifdevice) != 0 ) 
+      LOG_E(HW,"Could not start the IF device\n");
+  }
+
+  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
+  while (!oai_exit) {
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX, 0 );
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 0 );
+    start_meas( &softmodem_stats_rx_sf );
    
-   if (oai_exit) break;
+    if (oai_exit) break;
    
-   if ((((fp->frame_type == TDD )&&(subframe_select(fp,proc->subframe_rx)==SF_UL)) ||
-	(fp->frame_type == FDD))) {
-     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 1 );
-     // this spawns the prach inside and updates the frame and subframe counters
-     phy_procedures_eNB_common_RX(eNB, 0);
+    if ((((fp->frame_type == TDD )&&(subframe_select(fp,proc->subframe_rx)==SF_UL)) ||
+	 (fp->frame_type == FDD))) {
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 1 );
+      // this spawns the prach inside and updates the frame and subframe counters
+      phy_procedures_eNB_common_RX(eNB, 0);
+      
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 0 );
+    }
 
-     
-     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON, 0 );
-   }
-
-   // choose even or odd thread for RXn-TXnp4 processing 
-   eNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[proc->subframe_rx&1];
-
-   // wake up TX for subframe n+4
-   // lock the TX mutex and make sure the thread is ready
-   if (pthread_mutex_lock(&proc_rxtx->mutex_rxtx) != 0) {
-     LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n", proc_rxtx->instance_cnt_rxtx );
-     exit_fun( "error locking mutex_rxtx" );
-     break;
-   }
-   int cnt_rxtx = ++proc_rxtx->instance_cnt_rxtx;
-   // We have just received and processed the common part of a subframe, say n. 
-   // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired 
-   // transmitted timestamp of the next TX slot (first).
-   // The last (TS_rx mod samples_pexr_frame) was n*samples_per_tti, 
-   // we want to generate subframe (n+3), so TS_tx = TX_rx+3*samples_per_tti,
-   // and proc->subframe_tx = proc->subframe_rx+3
-   proc_rxtx->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti);
-   proc_rxtx->frame_rx     = proc->frame_rx;
-   proc_rxtx->subframe_rx  = proc->subframe_rx;
-   proc_rxtx->frame_tx     = (proc_rxtx->subframe_rx > 5) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx;
-   proc_rxtx->subframe_tx  = (proc_rxtx->subframe_rx + 4)%10;
+    // choose even or odd thread for RXn-TXnp4 processing 
+    eNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[proc->subframe_rx&1];
+
+    // wake up TX for subframe n+4
+    // lock the TX mutex and make sure the thread is ready
+    if (pthread_mutex_lock(&proc_rxtx->mutex_rxtx) != 0) {
+      LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n", proc_rxtx->instance_cnt_rxtx );
+      exit_fun( "error locking mutex_rxtx" );
+      break;
+    }
+    int cnt_rxtx = ++proc_rxtx->instance_cnt_rxtx;
+    // We have just received and processed the common part of a subframe, say n. 
+    // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired 
+    // transmitted timestamp of the next TX slot (first).
+    // The last (TS_rx mod samples_pexr_frame) was n*samples_per_tti, 
+    // we want to generate subframe (n+3), so TS_tx = TX_rx+3*samples_per_tti,
+    // and proc->subframe_tx = proc->subframe_rx+3
+    proc_rxtx->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti);
+    proc_rxtx->frame_rx     = proc->frame_rx;
+    proc_rxtx->subframe_rx  = proc->subframe_rx;
+    proc_rxtx->frame_tx     = (proc_rxtx->subframe_rx > 5) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx;
+    proc_rxtx->subframe_tx  = (proc_rxtx->subframe_rx + 4)%10;
    
-   pthread_mutex_unlock( &proc_rxtx->mutex_rxtx );
+    pthread_mutex_unlock( &proc_rxtx->mutex_rxtx );
    
-   if (cnt_rxtx == 0){
-     // the thread was presumably waiting where it should and can now be woken up
-     if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) {
-       LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n");
-       exit_fun( "ERROR pthread_cond_signal" );
-       break;
-     }
-   } else {
-     LOG_W( PHY,"[eNB] Frame %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, cnt_rxtx );
-     exit_fun( "TX thread busy" );
-     break;
-   }       
+    if (cnt_rxtx == 0) {
+      // the thread was presumably waiting where it should and can now be woken up
+      if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) {
+        LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n");
+        exit_fun( "ERROR pthread_cond_signal" );
+        break;
+      }
+    } else {
+      LOG_W( PHY,"[eNB] Frame %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, cnt_rxtx );
+      exit_fun( "TX thread busy" );
+      break;
+    }       
    
-   stop_meas( &softmodem_stats_rxtx_sf );
+
+    stop_meas( &softmodem_stats_rxtx_sf );
 #ifdef DEADLINE_SCHEDULER
-   if (opp_enabled){
-     if(softmodem_stats_rxtx_sf.diff_now/(cpuf) > attr.sched_runtime){
-       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RXTX_ENB, (softmodem_stats_rxtx_sf.diff_now/cpuf - attr.sched_runtime)/1000000.0);
-     }
-   }
+    if (opp_enabled){
+      if(softmodem_stats_rxtx_sf.diff_now/(cpuf) > attr.sched_runtime){
+	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RXTX_ENB, (softmodem_stats_rxtx_sf.diff_now/cpuf - attr.sched_runtime)/1000000.0);
+      }
+    }
 #endif // DEADLINE_SCHEDULER  
-   print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
-   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
-   
-
- }
- 
+    print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
+    
+    print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
+  }
  
 #ifdef DEBUG_THREADS
- printf( "Exiting eNB thread RXn-TXnp4\n");
+  printf( "Exiting eNB thread RXn-TXnp4\n");
 #endif
  
- eNB_thread_rx_status = 0;
- return &eNB_thread_rx_status;
+  eNB_thread_rx_status = 0;
+  return &eNB_thread_rx_status;
 }
 
 
-
 /*!
  * \brief The prach receive thread of eNB.
  * \param param is a \ref eNB_proc_t structure which contains the info what to process.
  * \returns a pointer to an int. The storage is not on the heap and must not be freed.
  */
-static void* eNB_thread_prach( void* param )
-{
+static void* eNB_thread_prach( void* param ) {
   static int eNB_thread_prach_status;
 
   eNB_proc_t *proc = (eNB_proc_t*)param;
@@ -842,7 +838,6 @@ static void* eNB_thread_prach( void* param )
   eNB_thread_prach_status = 0;
 
   MSC_START_USE();
-
     
 #ifdef DEADLINE_SCHEDULER
   struct sched_attr attr;
@@ -880,113 +875,102 @@ static void* eNB_thread_prach( void* param )
   /* Set CPU Affinity only if number of CPUs >2 */
   CPU_ZERO(&cpuset);
 #ifdef CPU_AFFINITY
-  if (get_nprocs() >2)
-  {
+  if (get_nprocs() >2) {
     for (j = 1; j < get_nprocs(); j++)
-       CPU_SET(j, &cpuset);
+      CPU_SET(j, &cpuset);
   
     s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-    if (s != 0)
-    {
+    if (s != 0) {
       perror( "pthread_setaffinity_np");  
       exit_fun (" Error setting processor affinity :");
     }
   }
 #endif //CPU_AFFINITY
-  /* Check the actual affinity mask assigned to the thread */
 
+  /* Check the actual affinity mask assigned to the thread */
   s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-  if (s != 0)
-  {
-     perror ("pthread_getaffinity_np");
-     exit_fun (" Error getting processor affinity :");
+  if (s != 0) {
+    perror ("pthread_getaffinity_np");
+    exit_fun (" Error getting processor affinity :");
   }
   memset(cpu_affinity,0, sizeof(cpu_affinity));
 
   for (j = 0; j < CPU_SETSIZE; j++)
-     if (CPU_ISSET(j, &cpuset))
-     {  
-        char temp[1024];
-        sprintf (temp, " CPU_%d", j);
-        strcat(cpu_affinity, temp);
-     }
-
+    if (CPU_ISSET(j, &cpuset)) {  
+      char temp[1024];
+      sprintf (temp, " CPU_%d", j);
+      strcat(cpu_affinity, temp);
+    }
 
   memset(&sparam, 0 , sizeof (sparam)); 
   sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-2;
 
   policy = SCHED_FIFO ; 
   s = pthread_setschedparam(pthread_self(), policy, &sparam);
-  if (s != 0)
-     {
-     perror("pthread_setschedparam : ");
-     exit_fun("Error setting thread priority");
-     }
+  if (s != 0) {
+    perror("pthread_setschedparam : ");
+    exit_fun("Error setting thread priority");
+  }
 
   memset(&sparam, 0 , sizeof (sparam));
 
   s = pthread_getschedparam(pthread_self(), &policy, &sparam);
-  if (s != 0)
-   {
-     perror("pthread_getschedparam");
-     exit_fun("Error getting thread priority");
-   }
-
+  if (s != 0) {
+    perror("pthread_getschedparam");
+    exit_fun("Error getting thread priority");
+  }
 
-  LOG_I( HW, "[SCHED][eNB] PRACH thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),
+  LOG_I(HW, "[SCHED][eNB] PRACH thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),
 	 (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
 	 (policy == SCHED_RR)    ? "SCHED_RR" :
 	 (policy == SCHED_OTHER) ? "SCHED_OTHER" :
 	 "???",
 	 sparam.sched_priority, cpu_affinity);
   
-  
 #endif // DEADLINE_SCHEDULER
 
- mlockall(MCL_CURRENT | MCL_FUTURE);
-
+  mlockall(MCL_CURRENT | MCL_FUTURE);
 
- while (!oai_exit) {
- 
-   
-   if (oai_exit) break;
+  while (!oai_exit) {
+    
+    if (oai_exit) break;
         
-   if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
-     LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH\n");
-     exit_fun( "error locking mutex" );
-     break;
-   }
-
-   while (proc->instance_cnt_prach < 0) {
-     // most of the time the thread is waiting here
-     // proc->instance_cnt_prach is -1
-     pthread_cond_wait( &proc->cond_prach, &proc->mutex_prach ); // this unlocks mutex_rxtx while waiting and then locks it again
-   }
-
-   if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
-     LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB PRACH\n");
-     exit_fun( "error unlocking mutex" );
-     break;
-   }
+    if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
+      LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH\n");
+      exit_fun( "error locking mutex" );
+      break;
+    }
+
+    while (proc->instance_cnt_prach < 0) {
+      // most of the time the thread is waiting here
+      // proc->instance_cnt_prach is -1
+      pthread_cond_wait( &proc->cond_prach, &proc->mutex_prach ); // this unlocks mutex_rxtx while waiting and then locks it again
+    }
+
+    if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
+      LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB PRACH\n");
+      exit_fun( "error unlocking mutex" );
+      break;
+    }
    
-   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1);
-   prach_procedures(eNB,0);
-   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1);
+    prach_procedures(eNB,0);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);
     
-   if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
-     LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH proc %d\n");
-     exit_fun( "error locking mutex" );
-     break;
-   }
-   
-   proc->instance_cnt_prach--;
+    if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
+      LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH proc %d\n");
+      exit_fun( "error locking mutex" );
+      break;
+    }
    
-   if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
-     LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n");
-     exit_fun( "error unlocking mutex" );
-     break;
-   }
- }
+    proc->instance_cnt_prach--;
+    
+    if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
+      LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n");
+      exit_fun( "error unlocking mutex" );
+      break;
+    } 
+  }
 
 #ifdef DEBUG_THREADS
   printf( "Exiting eNB thread PRACH\n");
@@ -997,10 +981,8 @@ static void* eNB_thread_prach( void* param )
 }
 
 
-
-
-void init_eNB_proc(void)
-{
+void init_eNB_proc(void) {
+  
   int i;
   int CC_id;
   PHY_VARS_eNB *eNB;
@@ -1010,7 +992,6 @@ void init_eNB_proc(void)
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     eNB = PHY_vars_eNB_g[0][CC_id];
 
-    
     proc = &eNB->proc;
     proc_rxtx = proc->proc_rxtx;
 #ifndef DEADLINE_SCHEDULER 
@@ -1074,7 +1055,6 @@ void init_eNB_proc(void)
     pthread_setname_np( proc->pthread_rx, name );
   }
   
-  
   /* setup PHY proc TX sync mechanism */
   pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL);
   pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL);
@@ -1085,8 +1065,8 @@ void init_eNB_proc(void)
 /*!
  * \brief Terminate eNB TX and RX threads.
  */
-void kill_eNB_proc(void)
-{
+void kill_eNB_proc(void) {
+
   int *status;
   PHY_VARS_eNB *eNB;
   eNB_proc_t *proc;
@@ -1110,6 +1090,7 @@ void kill_eNB_proc(void)
 #ifdef DEBUG_THREADS
     printf( "Joining eNB TX CC_id %d thread\n", CC_id);
 #endif
+
     int result,i;
     for (i=0;i<1;i++) {
       pthread_join( proc_rxtx[i].pthread_rxtx, (void**)&status );
@@ -1125,16 +1106,14 @@ void kill_eNB_proc(void)
 	  printf( "The thread was killed. No status available.\n" );
 	}
       }
-    
 #else
       UNUSED(result);
 #endif
 
       pthread_mutex_destroy( &proc_rxtx[i].mutex_rxtx );
       pthread_cond_destroy( &proc_rxtx[i].cond_rxtx );
-
-
     }
+
 #ifdef DEBUG_THREADS
     printf( "Killing RX CC_id %d thread\n", CC_id);
 #endif
@@ -1142,10 +1121,10 @@ void kill_eNB_proc(void)
 #ifdef DEBUG_THREADS
     printf( "Joining eNB RX CC_id %d thread ...\n", CC_id);
 #endif
+
     result = pthread_join( proc->pthread_rx, (void**)&status );
     
-#ifdef DEBUG_THREADS
-    
+#ifdef DEBUG_THREADS 
     if (result != 0) {
       printf( "Error joining thread.\n" );
     } else {
@@ -1154,8 +1133,7 @@ void kill_eNB_proc(void)
       } else {
 	printf( "The thread was killed. No status available.\n" );
       }
-    }
-    
+    }    
 #else
     UNUSED(result);
 #endif
@@ -1170,8 +1148,7 @@ void kill_eNB_proc(void)
    Each rf chain is is addressed by the card number and the chain on the card. The
    rf_map specifies for each CC, on which rf chain the mapping should start. Multiple
    antennas are mapped to successive RF chains on the same card. */
-int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs])
-{
+int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]) {
 
   int i, CC_id;
 
@@ -1179,7 +1156,6 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
 
   LTE_DL_FRAME_PARMS *frame_parms;
 
-
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     if (phy_vars_eNB[CC_id]) {
       frame_parms = &(phy_vars_eNB[CC_id]->frame_parms);
@@ -1198,8 +1174,6 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
         N_TA_offset = 624/4;
     }
 
-
-
     /*
     // replace RX signal buffers with mmaped HW versions
 #ifdef EXMIMO
@@ -1261,8 +1235,7 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
       rxdata[i] = (int32_t*)(32 + malloc16(32+openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
       phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = rxdata[i]-N_TA_offset; // N_TA offset for TDD         FIXME! N_TA_offset > 16 => access of unallocated memory
       memset(rxdata[i], 0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
-      printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->common_vars.rxdata[0][i],rxdata[i],N_TA_offset);
-      
+      printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->common_vars.rxdata[0][i],rxdata[i],N_TA_offset);      
     }
 
     for (i=0; i<frame_parms->nb_antennas_tx; i++) {
@@ -1271,7 +1244,6 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
       phy_vars_eNB[CC_id]->common_vars.txdata[0][i] = txdata[i];
       memset(txdata[i],0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
       printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->common_vars.txdata[0][i]);
-
     }
 
 
@@ -1281,9 +1253,8 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c
 }
 
 
-
-
 void reset_opp_meas(void) {
+
   int sfn;
   reset_meas(&softmodem_stats_mt);
   reset_meas(&softmodem_stats_hw);
@@ -1294,6 +1265,7 @@ void reset_opp_meas(void) {
   }
 }
 
+
 void print_opp_meas(void) {
 
   int sfn=0;
@@ -1309,7 +1281,6 @@ void print_opp_meas(void) {
 
 void init_eNB(eNB_func_t node_function) {
 
-
   int CC_id;
 
   for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++)
@@ -1339,11 +1310,11 @@ void stop_eNB() {
 #ifdef DEBUG_THREADS
   printf("Joining eNB_thread ...");
 #endif
-    int *eNB_thread_status_p;
-    int result = pthread_join( main_eNB_thread, (void**)&eNB_thread_status_p );
+
+  int *eNB_thread_status_p;
+  int result = pthread_join( main_eNB_thread, (void**)&eNB_thread_status_p );
 
 #ifdef DEBUG_THREADS
-  
   if (result != 0) {
     printf( "\nError joining main_eNB_thread.\n" );
   } else {
@@ -1353,7 +1324,6 @@ void stop_eNB() {
       printf( "The thread was killed. No status available.\n");
     }
   }
-  
 #else
   UNUSED(result);
 #endif // DEBUG_THREADS
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index 9f3655f02ed27bdca39eaea8935cf5df3ab2ff09..50ffc6e1ff348e416d9308000abab9938b6a0556 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -151,8 +151,6 @@ int sync_var=-1; //!< protected by mutex \ref sync_mutex.
 static pthread_t                forms_thread; //xforms
 #endif
 
-openair0_device openair0;
-
 uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
 uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
 
@@ -281,6 +279,9 @@ eth_params_t *eth_params;
 
 openair0_config_t openair0_cfg[MAX_CARDS];
 
+// Change to openair_global to handle UE
+openair0_device openair0;
+
 double cpuf;
 
 char uecap_xer[1024],uecap_xer_in=0;
@@ -1574,14 +1575,26 @@ int main( int argc, char **argv )
   }
   LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity);
 #endif
-
+  
+  openair0_cfg[0].log_level = glog_level;
+  
+  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+    PHY_vars_eNB_g[0][CC_id]->rfdevice.host_type = BBU_HOST;
+    PHY_vars_eNB_g[0][CC_id]->rfdevice.type = NONE_DEV;
+    PHY_vars_eNB_g[0][CC_id]->rfdevice.transp_type = NONE_TP;
+       
+    PHY_vars_eNB_g[0][CC_id]->ifdevice.host_type = BBU_HOST;
+    PHY_vars_eNB_g[0][CC_id]->ifdevice.type = NONE_DEV;
+    PHY_vars_eNB_g[0][CC_id]->ifdevice.transp_type = NONE_TP;
+  }
+  
   /* device host type is set*/
   openair0.host_type = BBU_HOST;
   /* device type is initialized NONE_DEV (no RF device) when the RF device will be initiated device type will be set */
   openair0.type = NONE_DEV;
   /* transport type is initialized NONE_TP (no transport protocol) when the transport protocol will be initiated transport protocol type will be set */
   openair0.transp_type = NONE_TP;
-  openair0_cfg[0].log_level = glog_level;
+  //openair0_cfg[0].log_level = glog_level;
   
   // Legacy BBU - RRH init  
   //int returns=-1;
@@ -1613,36 +1626,41 @@ int main( int argc, char **argv )
   //printf("Done\n");
   
   int returns=-1;
-  
+    
+  // Handle spatially distributed MIMO antenna ports   
   // Load RF device and initialize
-  if (node_function == eNodeB_3GPP || node_function == NGFI_RRU_IF4) { 
-    if (mode!=loop_through_memory) {
-      returns=openair0_device_load(&openair0, &openair0_cfg[0]);
-      printf("openair0_device_init returns %d\n",returns);
-      if (returns<0) {
-	      printf("Exiting, cannot initialize device\n");
-	      exit(-1);
+  if (node_function != NGFI_RCC_IF4) { 
+    for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {  
+      if (mode!=loop_through_memory) {
+        returns=openair0_device_load(&(PHY_vars_eNB_g[0][CC_id]->rfdevice), &openair0_cfg[0]);
+        printf("openair0_device_init returns %d for CC_id %d\n",returns,CC_id);
+        if (returns<0) {
+	        printf("Exiting, cannot initialize device\n");
+	        exit(-1);
+        }
       }
-    }
-    else if (mode==loop_through_memory) {    
+      else if (mode==loop_through_memory) {    
+      }    
     }
   }  
   
   // Load transport protocol and initialize
-  if (node_function == NGFI_RCC_IF4 || node_function == NGFI_RRU_IF4){ 
-    if (mode!=loop_through_memory) {
-      returns=openair0_transport_load(&openair0, &openair0_cfg[0], eth_params);
-      printf("openair0_transport_init returns %d\n",returns);
-      if (returns<0) { 
-	      printf("Exiting, cannot initialize transport protocol\n");
-	      exit(-1);
+  if (node_function != eNodeB_3GPP){ 
+    for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {  
+      if (mode!=loop_through_memory) {
+        returns=openair0_transport_load(&(PHY_vars_eNB_g[0][CC_id]->ifdevice), &openair0_cfg[0], (eth_params+CC_id));
+        printf("openair0_transport_init returns %d for CC_id %d\n",returns,CC_id);
+        if (returns<0) {
+	        printf("Exiting, cannot initialize transport protocol\n");
+	        exit(-1);
+        }
       }
+      else if (mode==loop_through_memory) {    
+      }    
     }
-    else if (mode==loop_through_memory) {    
-    }
-  }   
+  }
 
-  printf("Done\n");
+  printf("Done initializing RF and IF devices\n");
   
   mac_xface = malloc(sizeof(MAC_xface));
 
@@ -1812,7 +1830,7 @@ int main( int argc, char **argv )
 
 
 
-
+// *** Handle per CC_id openair0
 #ifndef USRP_DEBUG
   if ((UE_flag==1) && (mode!=loop_through_memory))
     if (openair0.trx_start_func(&openair0) != 0 ) 
@@ -1882,7 +1900,7 @@ int main( int argc, char **argv )
   pthread_cond_destroy(&sync_cond);
   pthread_mutex_destroy(&sync_mutex);
 
-
+  // *** Handle per CC_id openair0
   openair0.trx_end_func(&openair0);
 
   if (ouput_vcd)