diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 5c9ab6d99df7c15d8b4732aff73bd83402e11794..50acfc4ce6c3a5524303050c1970b1da1e9fb6ff 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -519,6 +519,9 @@ add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4
 add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4")
 
 add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "EXMIMO" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR" "OAI_SIMU")
+if (NOT ${RF_BOARD} STREQUAL "None")
+   add_definitions(-DMANAGED_RF=1)
+endif()
 
 
 add_list2_option(TRANSP_PRO "None" "Transport protocol type" "None" "ETHERNET")
@@ -627,8 +630,6 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
 add_library(tcp_bridge_oai MODULE ${HWLIB_TCP_BRIDGE_OAI_SOURCE} )
 set_target_properties(tcp_bridge_oai PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
 
-add_library(rfsimulator MODULE ${OPENAIR_TARGETS}/ARCH/rfsimulator/simulator.c)
-
 ##########################################################
 
 include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
@@ -2010,6 +2011,11 @@ add_library(uescope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_
 target_link_libraries(enbscope ${XFORMS_LIBRARIES})
 target_link_libraries(uescope ${XFORMS_LIBRARIES})
 
+add_library(rfsimulator MODULE 
+	${OPENAIR_TARGETS}/ARCH/rfsimulator/simulator.c
+	)
+target_link_libraries(rfsimulator SIMU ${ATLAS_LIBRARIES})
+
 set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}")
 
 #include T directory even if the T is off because T macros are in the code
@@ -2053,6 +2059,25 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
 #################################
 # add executables for operation
 #################################
+add_library(minimal_lib
+  ${OPENAIR_DIR}/common/utils/backtrace.c
+  ${OPENAIR_DIR}/common/utils/LOG/log.c
+  ${OPENAIR_DIR}/common/config/config_userapi.c
+  ${OPENAIR_DIR}/common/config/config_load_configmodule.c
+  ${OPENAIR_DIR}/common/config/config_cmdline.c
+  ${OPENAIR_DIR}/common/utils/minimal_stub.c
+  ${T_SOURCE}
+  )
+target_link_libraries(minimal_lib pthread dl ${T_LIB})
+
+add_executable(replay_node
+  ${OPENAIR_TARGETS}/ARCH/rfsimulator/stored_node.c
+  )
+target_link_libraries (replay_node minimal_lib)
+
+add_executable(measurement_display
+  ${OPENAIR_DIR}/common/utils/threadPool/measurement_display.c)
+target_link_libraries (measurement_display minimal_lib)
 
 # lte-softmodem is both eNB and UE implementation
 ###################################################
diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c
index 66d3078d333cc3b697d5ee9ae81b406e213cf064..65e7a6dcc23c6e0ed760ef885c0f8dff186919b9 100644
--- a/common/config/config_userapi.c
+++ b/common/config/config_userapi.c
@@ -450,7 +450,7 @@ int config_setdefault_double(paramdef_t *cfgoptions, char *prefix) {
   config_check_valptr(cfgoptions, (char **)&(cfgoptions->dblptr),sizeof(double));
 
   if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
-    *(cfgoptions->u64ptr)=cfgoptions->defdblval;
+    *(cfgoptions->dblptr)=cfgoptions->defdblval;
     status=1;
     printf_params("[CONFIG] %s set to default value %lf\n",cfgoptions->optname , *(cfgoptions->dblptr));
   }
diff --git a/common/utils/minimal_stub.c b/common/utils/minimal_stub.c
new file mode 100644
index 0000000000000000000000000000000000000000..86454fe53f87dad750a11d7c0a1f07d67b5e5379
--- /dev/null
+++ b/common/utils/minimal_stub.c
@@ -0,0 +1,4 @@
+int T_stdout;
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+}
diff --git a/common/utils/simple_executable.h b/common/utils/simple_executable.h
new file mode 100644
index 0000000000000000000000000000000000000000..98b75012dff61df05c20328904779734f2609067
--- /dev/null
+++ b/common/utils/simple_executable.h
@@ -0,0 +1,37 @@
+#ifndef __SIMPLE_EXE_H__
+#define __SIMPLE_EXE_H__
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <common/utils/assertions.h>
+#include <common/utils/LOG/log.h>
+#include "common_lib.h"
+
+#ifdef T
+  #undef T
+  #define T(...)
+#endif
+
+#endif
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 3f81816aa1022de2a623cb8bc865cadb0f9e74cd..c1685e11ecd5beab3aeed890c8fee63a634132c1 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -42,35 +42,35 @@
 int set_device(openair0_device *device) {
   switch (device->type) {
     case EXMIMO_DEV:
-      printf("[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case USRP_B200_DEV:
-      printf("[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case USRP_X300_DEV:
-      printf("[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case BLADERF_DEV:
-      printf("[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case LMSSDR_DEV:
-      printf("[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case IRIS_DEV:
-      printf("[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case NONE_DEV:
-      printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     default:
-      printf("[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_E(HW,"[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return -1;
   }
 
@@ -80,17 +80,17 @@ int set_device(openair0_device *device) {
 int set_transport(openair0_device *device) {
   switch (device->transp_type) {
     case ETHERNET_TP:
-      printf("[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return 0;
       break;
 
     case NONE_TP:
-      printf("[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return 0;
       break;
 
     default:
-      printf("[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_E(HW,"[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return -1;
       break;
   }
@@ -119,7 +119,7 @@ int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_param
   ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
 
   if (ret < 0) {
-    fprintf(stderr,"Library %s couldn't be loaded\n",libname);
+    LOG_E(HW,"Library %s couldn't be loaded\n",libname);
   } else {
     ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
   }
@@ -135,7 +135,7 @@ int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cf
 
   if ( rc >= 0) {
     if ( set_device(device) < 0) {
-      fprintf(stderr, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
+      LOG_E(HW, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
       return -1;
     }
   }
@@ -149,7 +149,7 @@ int openair0_transport_load(openair0_device *device, openair0_config_t *openair0
 
   if ( rc >= 0) {
     if ( set_transport(device) < 0) {
-      fprintf(stderr, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
+      LOG_E(HW, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
       return -1;
     }
   }
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index 0af6fa9c5edb89be8dfd193c1692a0f072ea5f90..aca332ac480e368806090ab553317267caa81b30 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -34,6 +34,7 @@
 #define COMMON_LIB_H
 #include <stdint.h>
 #include <sys/types.h>
+#include <openair1/PHY/TOOLS/tools_defs.h>
 
 /* name of shared library implementing the radio front end */
 #define OAI_RF_LIBNAME        "oai_device"
@@ -83,9 +84,6 @@ typedef enum {
  */
 /*!\brief RF device types
  */
-#ifdef OCP_FRAMEWORK
-#include <enums.h>
-#else
 typedef enum {
   MIN_RF_DEV_TYPE = 0,
   /*!\brief device is ExpressMIMO */
@@ -102,10 +100,13 @@ typedef enum {
   IRIS_DEV,
   /*!\brief device is NONE*/
   NONE_DEV,
+  /*!\brief device is ADRV9371_ZC706 */
+  ADRV9371_ZC706_DEV,
+  /*!\brief device is UEDv2 */
+  UEDv2_DEV,
   MAX_RF_DEV_TYPE
 
 } dev_type_t;
-#endif
 
 /*!\brief transport protocol types
  */
@@ -384,6 +385,31 @@ struct openair0_device_t {
 typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg);
 /* type of transport init function, implemented in shared lib */
 typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
+#define UE_MAGICDL_FDD 0xA5A5A5A5A5A5A5A5  // UE DL FDD record
+#define UE_MAGICUL_FDD 0x5A5A5A5A5A5A5A5A  // UE UL FDD record
+#define UE_MAGICDL_TDD 0xA6A6A6A6A6A6A6A6  // UE DL TDD record
+#define UE_MAGICUL_TDD 0x6A6A6A6A6A6A6A6A  // UE UL TDD record
+
+#define ENB_MAGICDL_FDD 0xB5B5B5B5B5B5B5B5  // eNB DL FDD record
+#define ENB_MAGICUL_FDD 0x5B5B5B5B5B5B5B5B  // eNB UL FDD record
+#define ENB_MAGICDL_TDD 0xB6B6B6B6B6B6B6B6  // eNB DL TDD record
+#define ENB_MAGICUL_TDD 0x6B6B6B6B6B6B6B6B  // eNB UL TDD record
+
+#define OPTION_LZ4  0x00000001          // LZ4 compression (option_value is set to compressed size)
+
+#define sample_t struct complex16 // 2*16 bits complex number
+
+typedef struct {
+  uint64_t magic;          // Magic value (see defines above)
+  uint32_t size;           // Number of samples per antenna to follow this header
+  uint32_t nbAnt;          // Total number of antennas following this header
+  // Samples per antenna follow this header,
+  // i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1
+  // data following this header in bytes is nbAnt*size*sizeof(sample_t)
+  uint64_t timestamp;      // Timestamp value of first sample
+  uint32_t option_value;   // Option value
+  uint32_t option_flag;    // Option flag
+} samplesBlockHeader_t;
 
 #ifdef __cplusplus
 extern "C"
diff --git a/targets/ARCH/rfsimulator/README.md b/targets/ARCH/rfsimulator/README.md
index ebe7d72ee05860907e1c3b5315bb84270d0879b6..68b820ff9ac13419204b927fb229d00489ac022f 100644
--- a/targets/ARCH/rfsimulator/README.md
+++ b/targets/ARCH/rfsimulator/README.md
@@ -1,14 +1,26 @@
-## General
-
+#General
 This is a RF simulator that allows to test OAI without a RF board.
 It replaces a actual RF board driver.
 
 As much as possible, it works like a RF board, but not in realtime: it can run faster than realtime if there is enough CPU or slower (it is CPU bound instead of real time RF sampling bound)
 
-## build
+#build
 
- No specific build is required, use the [oai softmodem build procedure](../../../doc/BUILD.md)
+## From build_oai
+You can build it the same way, and together with actual RF driver
 
+Example:
+```bash
+./build_oai --ue-nas-use-tun --UE --eNB -w SIMU
+```
+It is also possible to build actual RF and use choose on each run:
+```bash
+./build_oai --ue-nas-use-tun --UE --eNB -w USRP --rfsimulator
+```
+Will build both the eNB (lte-softmodem) and the UE (lte-uesoftmodem)
+We recommend to use the option --ue-nas-use-tun that is much simpler to use than the OAI kernel driver.
+
+## Add the rfsimulator after initial build
 After any regular build, you can compile the driver
 ```bash
 cd <the_compilation_dir_from_bouild_oai_script>/build
@@ -18,35 +30,21 @@ Then, you can use it freely
 
 # Usage
 Setting the env variable RFSIMULATOR enables the RF board simulator
-It should the set to "enb" in the eNB
+It should the set to "server" in the eNB or gNB
 
 ## 4G case
 For the UE, it should be set to the IP address of the eNB
 example: 
-
 ```bash
-sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50 --rfsim
+sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50 
 ```
-For the eNodeB, use a valid configuration file setup for USRP board tests and start the softmodem as usual, but adding the `--rfsim` option.
-
-
-
-```bash
-sudo RFSIMULATOR=enb ./lte-softmodem -O <config file> --rfsim
-```
-
-
-
 Except this, the UE and the eNB can be used as it the RF is real
 
 If you reach 'RA not active' on UE, be careful to generate a valid SIM
 ```bash
 $OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
 ```
-This simulator can also be used with the `--noS1` option, in this case you must run the eNodeB and the UE on different PCs. 
-
 ## 5G case
-
 After regular build, add the simulation driver
 (don't use ./build_oai -w SIMU until we merge 4G and 5G branches)
 ```bash
@@ -55,7 +53,7 @@ make rfsimulator
 ```
 ### Launch gNB in one window
 ```bash
-sudo RFSIMULATOR=enb ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD
+sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD
 ```
 ### Launch UE in another window
 ```bash
@@ -64,8 +62,40 @@ sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000
 Of course, set the gNB machine IP address if the UE and the gNB are not on the same machine
 In UE, you can add "-d" to get the softscope
 
-## Caveacts
+### store and replay
 
-Still issues in power control: txgain, rxgain are not used
+You can store emitted I/Q samples:
 
+If you set the environment variable: saveIQfile to a file name
+The simulator will write all IQ samples into this file
+
+Then, you can replay with the executable "replay_node"
+
+First compile it, as the other binaries
+```
+make replay_node
+```
+You can use this binary as I/Q data source to feed whatever UE or NB with recorded I/Q samples.
+
+The file format is successive blocks of a header followed by the I/Q array.
+If you have existing stored I/Q, you can adpat the tool "replay_node" to convert your format to the rfsimulator format.
+
+The format intend to be compatible with the OAI store/replay feature on USRP
+
+### Channel simulation
+The RF channel simulator is called.
+In current version all channel paramters are hard coded in the call to:
+```
+new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
+                                          AWGN,
+                                          bridge->sample_rate,
+                                          bridge->tx_bw,
+                                          0.0, // forgetting_factor
+                                          0, // maybe used for TA
+                                          0); // path_loss in dB
+```
+Only the input noise can be changed on command line with -s parameter.
+With path loss = 0 set "-s 5" to see a little noise
 
+#Caveacts
+Still issues in power control: txgain, rxgain are not used
\ No newline at end of file
diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c
index a17327b03ecc5791cadc7cef76fbecc9d3205da8..e81e958184e4b73afbcd4782f26b15b724850492 100644
--- a/targets/ARCH/rfsimulator/simulator.c
+++ b/targets/ARCH/rfsimulator/simulator.c
@@ -3,6 +3,12 @@
   copyleft: OpenAirInterface Software Alliance and it's licence
 */
 
+/*
+ * Open issues and limitations
+ * The read and write should be called in the same thread, that is not new USRP UHD design
+ * When the opposite side switch from passive reading to active R+Write, the synchro is not fully deterministic
+ */
+
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -21,63 +27,175 @@
 #include "common_lib.h"
 #include <openair1/PHY/defs_eNB.h>
 #include "openair1/PHY/defs_UE.h"
+#include <openair1/SIMULATION/TOOLS/sim.h>
 
 #define PORT 4043 //TCP port for this simulator
 #define CirSize 3072000 // 100ms is enough
-#define sample_t uint32_t // 2*16 bits complex number
 #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
 #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
-#define MAGICeNB 0xA5A5A5A5A5A5A5A5
-#define MAGICUE  0x5A5A5A5A5A5A5A5A
 
-typedef struct {
-  uint64_t magic;
-  uint32_t size;
-  uint32_t nbAnt;
-  uint64_t timestamp;
-} transferHeader;
+#define MAX_SIMULATION_CONNECTED_NODES 5
+#define GENERATE_CHANNEL 10 //each frame in DL
+
+// Fixme: datamodel, external variables in .h files, ...
+#include <common/ran_context.h>
+extern double snr_dB;
+extern RAN_CONTEXT_t RC;
+//
+
+pthread_mutex_t Sockmutex;
 
 typedef struct buffer_s {
   int conn_sock;
   bool alreadyRead;
   uint64_t lastReceivedTS;
   bool headerMode;
-  transferHeader th;
+  samplesBlockHeader_t th;
   char *transferPtr;
   uint64_t remainToTransfer;
   char *circularBufEnd;
   sample_t *circularBuf;
+  channel_desc_t *channel_model;
 } buffer_t;
 
 typedef struct {
   int listen_sock, epollfd;
   uint64_t nextTimestamp;
   uint64_t typeStamp;
-  uint64_t initialAhead;
   char *ip;
+  int saveIQfile;
   buffer_t buf[FD_SETSIZE];
+  int rx_num_channels;
+  int tx_num_channels;
+  double sample_rate;
+  double tx_bw;
 } rfsimulator_state_t;
 
+/*
+  Legacy study:
+  The parameters are:
+  gain&loss (decay, signal power, ...)
+  either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
+  => don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
+  will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
+  lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
+  a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain
+
+  multi_path (auto convolution, ISI, ...)
+  either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
+  legacy: we regenerate each sub frame in UL, and each frame only in DL
+*/
+void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
+                 int rxAnt,
+                 channel_desc_t *channelDesc,
+                 int nbSamples,
+                 uint64_t TS
+               ) {
+  // channelDesc->path_loss_dB should contain the total path gain
+  // so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
+  // UE and NB gain control to be added
+  // Fixme: not sure when it is "volts" so dB is 20*log10(...) or "power", so dB is 10*log10(...)
+  const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
+  // Energy in one sample to calibrate input noise
+  //Fixme: modified the N0W computation, not understand the origin value
+  const double KT=1.38e-23*290; //Boltzman*temperature
+  // sampling rate is linked to acquisition band (the input pass band filter)
+  const double noise_figure_watt = KT*channelDesc->sampling_rate;
+  // Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
+  // the parameter "-s" is declared as SNR, but the input power is not well defined
+  // −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
+  const double rxGain= 132.24 - snr_dB; 
+  // sqrt(4*noise_figure_watt) is the thermal noise factor (volts)
+  // fixme: the last constant is pure trial results to make decent noise 
+  const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10;
+  // Fixme: we don't fill the offset length samples at begining ?
+  // anyway, in today code, channel_offset=0
+  const int dd = abs(channelDesc->channel_offset);
+  const int nbTx=channelDesc->nb_tx;
+
+  for (int i=0; i<((int)nbSamples-dd); i++) {
+    struct complex16 *out_ptr=after_channel_sig+dd+i;
+    struct complex rx_tmp= {0};
+
+    for (int txAnt=0; txAnt < nbTx; txAnt++) {
+      const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];
+
+      //const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
+      for (int l = 0; l<(int)channelDesc->channel_length; l++) {
+        // let's assume TS+i >= l
+        // fixme: the rfsimulator current structure is interleaved antennas
+        // this has been designed to not have to wait a full block transmission
+        // but it is not very usefull
+        // it would be better to split out each antenna in a separate flow
+        // that will allow to mix ru antennas freely
+        struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
+        rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
+        rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
+      } //l
+    }
+
+    out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
+      printf("in: %d, out %d= %f*%f + %f*%f\n",
+      input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x,
+      pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0));
+    out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
+    out_ptr++;
+  }
+
+  if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
+    // Cast to a wrong type for compatibility !
+    LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
+          10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
+          10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
+          channelDesc->path_loss_dB,
+          10*log10(noise_per_sample));
+}
+
 void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
   buffer_t *ptr=&bridge->buf[sock];
   AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, "");
   ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1);
   ptr->conn_sock=sock;
+  ptr->alreadyRead=false;
+  ptr->lastReceivedTS=0;
   ptr->headerMode=true;
   ptr->transferPtr=(char *)&ptr->th;
-  ptr->remainToTransfer=sizeof(transferHeader);
+  ptr->remainToTransfer=sizeof(samplesBlockHeader_t);
   int sendbuff=1000*1000*10;
   AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, "");
   struct epoll_event ev= {0};
   ev.events = EPOLLIN | EPOLLRDHUP;
   ev.data.fd = sock;
   AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD,  sock, &ev) != -1, "");
+  // create channel simulation model for this mode reception
+  // snr_dB is pure global, coming from configuration paramter "-s"
+  // Fixme: referenceSignalPower should come from the right place
+  // but the datamodel is inconsistant
+  // legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
+  // (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
+  // Legacy sets it as:
+  // ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
+  // we use directly the paramter passed on the command line ("-s")
+  // the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
+  // Legacy changes directlty the variable channel_model->path_loss_dB place to place
+  // while calling new_channel_desc_scm() with path losses = 0
+  ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
+                                          AWGN,
+                                          bridge->sample_rate,
+                                          bridge->tx_bw,
+                                          0.0, // forgetting_factor
+                                          0, // maybe used for TA
+                                          0); // path_loss in dB
+  random_channel(ptr->channel_model,false);
 }
 
 void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
   AssertFatal( epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL,  sock, NULL) != -1, "");
   close(sock);
   free(bridge->buf[sock].circularBuf);
+  // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
+  // a lot of mem leaks
+  free(bridge->buf[sock].channel_model);
   memset(&bridge->buf[sock], 0, sizeof(buffer_t));
   bridge->buf[sock].conn_sock=-1;
 }
@@ -87,12 +205,11 @@ void socketError(rfsimulator_state_t *bridge, int sock) {
     LOG_W(HW,"Lost socket \n");
     removeCirBuf(bridge, sock);
 
-    if (bridge->typeStamp==MAGICUE)
+    if (bridge->typeStamp==UE_MAGICDL_FDD)
       exit(1);
   }
 }
 
-
 #define helpTxt "\
 \x1b[31m\
 rfsimulator: error: you have to run one UE and one eNB\n\
@@ -117,11 +234,18 @@ void setblocking(int sock, enum blocking_t active) {
   AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
 }
 
-static bool flushInput(rfsimulator_state_t *t);
+static bool flushInput(rfsimulator_state_t *t, int timeout);
 
-void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
+void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
+  if (t->saveIQfile != -1) {
+    if (write(t->saveIQfile, _buf, count) != count )
+      LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno));
+  }
+
+  AssertFatal(fd>=0 && _buf && count >0 && t,
+              "Bug: %d/%p/%zd/%p", fd, _buf, count, t);
   char *buf = _buf;
-  int l;
+  ssize_t l;
   setblocking(fd, notBlocking);
 
   while (count) {
@@ -132,7 +256,9 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
         continue;
 
       if(errno==EAGAIN) {
-        flushInput(t);
+        // The opposite side is saturated
+        // we read incoming sockets meawhile waiting
+        flushInput(t, 5);
         continue;
       } else
         return;
@@ -145,7 +271,7 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
 
 int server_start(openair0_device *device) {
   rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
-  t->typeStamp=MAGICeNB;
+  t->typeStamp=ENB_MAGICDL_FDD;
   AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
   int enable = 1;
   AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
@@ -168,7 +294,7 @@ sin_addr:
 
 int start_ue(openair0_device *device) {
   rfsimulator_state_t *t = device->priv;
-  t->typeStamp=MAGICUE;
+  t->typeStamp=UE_MAGICDL_FDD;
   int sock;
   AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
   struct sockaddr_in addr = {
@@ -200,14 +326,16 @@ sin_addr:
   return 0;
 }
 
+uint64_t lastW=-1;
 int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
   rfsimulator_state_t *t = device->priv;
+  LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
 
   for (int i=0; i<FD_SETSIZE; i++) {
     buffer_t *ptr=&t->buf[i];
 
     if (ptr->conn_sock >= 0 ) {
-      transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp};
+      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
       fullwrite(ptr->conn_sock,&header, sizeof(header), t);
       sample_t tmpSamples[nsamps][nbAnt];
 
@@ -223,21 +351,27 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi
     }
   }
 
+  lastW=timestamp;
   LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
         nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) );
+  // Let's verify we don't have incoming data
+  // This is mandatory when the opposite side don't transmit
+  // This is mandatory when the opposite side don't transmit
+  flushInput(t, 0);
+  pthread_mutex_unlock(&Sockmutex);
   return nsamps;
 }
 
-static bool flushInput(rfsimulator_state_t *t) {
+static bool flushInput(rfsimulator_state_t *t, int timeout) {
   // Process all incoming events on sockets
   // store the data in lists
   struct epoll_event events[FD_SETSIZE]= {0};
-  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200);
+  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
 
   if ( nfds==-1 ) {
-    if ( errno==EINTR || errno==EAGAIN )
+    if ( errno==EINTR || errno==EAGAIN ) {
       return false;
-    else
+    } else
       AssertFatal(false,"error in epoll_wait\n");
   }
 
@@ -263,7 +397,7 @@ static bool flushInput(rfsimulator_state_t *t) {
         continue;
       }
 
-      int blockSz;
+      ssize_t blockSz;
 
       if ( b->headerMode)
         blockSz=b->remainToTransfer;
@@ -272,7 +406,7 @@ static bool flushInput(rfsimulator_state_t *t) {
                  b->remainToTransfer :
                  b->circularBufEnd - 1 - b->transferPtr ;
 
-      int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
+      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
 
       if ( sz < 0 ) {
         if ( errno != EAGAIN ) {
@@ -282,6 +416,7 @@ static bool flushInput(rfsimulator_state_t *t) {
       } else if ( sz == 0 )
         continue;
 
+      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
       AssertFatal((b->remainToTransfer-=sz) >= 0, "");
       b->transferPtr+=sz;
 
@@ -290,39 +425,44 @@ static bool flushInput(rfsimulator_state_t *t) {
 
       // check the header and start block transfer
       if ( b->headerMode==true && b->remainToTransfer==0) {
-        AssertFatal( (t->typeStamp == MAGICUE  && b->th.magic==MAGICeNB) ||
-                     (t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol");
+        AssertFatal( (t->typeStamp == UE_MAGICDL_FDD  && b->th.magic==ENB_MAGICDL_FDD) ||
+                     (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol");
         b->headerMode=false;
         b->alreadyRead=true;
 
         if ( b->lastReceivedTS != b->th.timestamp) {
           int nbAnt= b->th.nbAnt;
 
-          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ )
-            for (int a=0; a < nbAnt; a++)
-              b->circularBuf[(index*nbAnt+a)%CirSize]=0;
+          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) {
+            for (int a=0; a < nbAnt; a++) {
+              b->circularBuf[(index*nbAnt+a)%CirSize].r=0;
+              b->circularBuf[(index*nbAnt+a)%CirSize].i=0;
+            }
+          }
 
           LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS );
         }
 
         b->lastReceivedTS=b->th.timestamp;
+        AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize),
+                    "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS);
         b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize];
         b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
       }
 
       if ( b->headerMode==false ) {
+        LOG_D(HW,"Set b->lastReceivedTS %ld\n", b->lastReceivedTS);
         b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
 
+        // First block in UE, resync with the eNB current TS
+        if ( t->nextTimestamp == 0 )
+          t->nextTimestamp=b->lastReceivedTS-b->th.size;
+
         if ( b->remainToTransfer==0) {
           LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS);
-
-          // First block in UE, resync with the eNB current TS
-          if ( t->nextTimestamp == 0 )
-            t->nextTimestamp=b->lastReceivedTS-b->th.size;
-
           b->headerMode=true;
           b->transferPtr=(char *)&b->th;
-          b->remainToTransfer=sizeof(transferHeader);
+          b->remainToTransfer=sizeof(samplesBlockHeader_t);
           b->th.magic=-1;
         }
       }
@@ -334,10 +474,10 @@ static bool flushInput(rfsimulator_state_t *t) {
 
 int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
   if (nbAnt != 1) {
-    LOG_E(HW, "rfsimulator: only 1 antenna tested\n");
-    exit(1);
+    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
   }
 
+  pthread_mutex_lock(&Sockmutex);
   rfsimulator_state_t *t = device->priv;
   LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps);
   // deliver data from received data
@@ -350,13 +490,14 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
 
   if ( first_sock ==  FD_SETSIZE ) {
     // no connected device (we are eNB, no UE is connected)
-    if (!flushInput(t)) {
+    if (!flushInput(t, 10)) {
       for (int x=0; x < nbAnt; x++)
         memset(samplesVoid[x],0,sampleToByte(nsamps,1));
 
       t->nextTimestamp+=nsamps;
       LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
       *ptimestamp = t->nextTimestamp-nsamps;
+      pthread_mutex_unlock(&Sockmutex);
       return nsamps;
     }
   } else {
@@ -365,20 +506,21 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
     do {
       have_to_wait=false;
 
-      for ( int sock=0; sock<FD_SETSIZE; sock++)
-        if ( t->buf[sock].circularBuf &&
-             t->buf[sock].alreadyRead && //>= t->initialAhead &&
-             (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
-          have_to_wait=true;
-          break;
-        }
+      for ( int sock=0; sock<FD_SETSIZE; sock++) {
+        if ( t->buf[sock].circularBuf && t->buf[sock].alreadyRead )
+          if ( t->buf[sock].lastReceivedTS == 0 ||
+               (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
+            have_to_wait=true;
+            break;
+          }
+      }
 
       if (have_to_wait)
         /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
           ptr->lastReceivedTS,
           t->nextTimestamp+nsamps);
         */
-        flushInput(t);
+        flushInput(t, 3);
     } while (have_to_wait);
   }
 
@@ -386,17 +528,25 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
   for (int a=0; a<nbAnt; a++)
     memset(samplesVoid[a],0,sampleToByte(nsamps,1));
 
-  // Add all input signal in the output buffer
+  // Add all input nodes signal in the output buffer
   for (int sock=0; sock<FD_SETSIZE; sock++) {
     buffer_t *ptr=&t->buf[sock];
 
     if ( ptr->circularBuf && ptr->alreadyRead ) {
-      for (int a=0; a<nbAnt; a++) {
-        sample_t *out=(sample_t *)samplesVoid[a];
-
-        for ( int i=0; i < nsamps; i++ )
-          out[i]+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize]<<1;
-      }
+      bool reGenerateChannel=false;
+
+      //fixme: when do we regenerate
+      // it seems legacy behavior is: never in UL, each frame in DL
+      if (reGenerateChannel)
+        random_channel(ptr->channel_model,0);
+
+      for (int a=0; a<nbAnt; a++)
+        rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
+                    a,
+                    ptr->channel_model,
+                    nsamps,
+                    t->nextTimestamp
+                  );
     }
   }
 
@@ -406,10 +556,9 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
         nsamps,
         *ptimestamp, t->nextTimestamp,
         signal_energy(samplesVoid[0], nsamps));
+  pthread_mutex_unlock(&Sockmutex);
   return nsamps;
 }
-
-
 int rfsimulator_request(openair0_device *device, void *msg, ssize_t msg_len) {
   abort();
   return 0;
@@ -434,11 +583,11 @@ int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cf
 int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
   return 0;
 }
-
-
 __attribute__((__visibility__("default")))
 int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
-  //set_log(HW,OAILOG_DEBUG);
+  // to change the log level, use this on command line
+  // --log_config.hw_log_level debug
+  // (for phy layer, replace "hw" by "phy"
   rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
 
   if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) {
@@ -446,11 +595,28 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
     exit(1);
   }
 
-  rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ?
-                           MAGICeNB:
-                           MAGICUE;
-  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE");
-  device->trx_start_func       = rfsimulator->typeStamp == MAGICeNB ?
+  pthread_mutex_init(&Sockmutex, NULL);
+
+  if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
+       strncasecmp(rfsimulator->ip,"server",3) == 0 )
+    rfsimulator->typeStamp = ENB_MAGICDL_FDD;
+  else
+    rfsimulator->typeStamp = UE_MAGICDL_FDD;
+
+  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
+  char *saveF;
+
+  if ((saveF=getenv("saveIQfile")) != NULL) {
+    rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
+
+    if ( rfsimulator->saveIQfile != -1 )
+      LOG_I(HW,"rfsimulator: will save written IQ samples  in %s\n", saveF);
+    else
+      LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
+  } else
+    rfsimulator->saveIQfile = -1;
+
+  device->trx_start_func       = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
                                  server_start :
                                  start_ue;
   device->trx_get_stats_func   = rfsimulator_get_stats;
@@ -470,6 +636,12 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
     rfsimulator->buf[i].conn_sock=-1;
 
   AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
-  rfsimulator->initialAhead=openair0_cfg[0].sample_rate/1000; // One sub frame
+  // initialize channel simulation
+  rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels;
+  rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels;
+  rfsimulator->sample_rate=openair0_cfg->sample_rate;
+  rfsimulator->tx_bw=openair0_cfg->tx_bw;
+  randominit(0);
+  set_taus_seed(0);
   return 0;
 }
diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c
new file mode 100644
index 0000000000000000000000000000000000000000..888b5f6de0d2d1224ed99c0fe34d49f1900b312e
--- /dev/null
+++ b/targets/ARCH/rfsimulator/stored_node.c
@@ -0,0 +1,142 @@
+/*
+  Author: Laurent THOMAS, Open Cells
+  copyleft: OpenAirInterface Software Alliance and it's licence
+*/
+
+#include <common/utils/simple_executable.h>
+
+
+void fullwrite(int fd, void *_buf, int count) {
+  char *buf = _buf;
+  int l;
+
+  while (count) {
+    l = write(fd, buf, count);
+
+    if (l <= 0) {
+      if (errno==EINTR)
+        continue;
+
+      if(errno==EAGAIN) {
+        continue;
+      } else {
+        AssertFatal(false,"Lost socket\n");
+      }
+    } else {
+      count -= l;
+      buf += l;
+    }
+  }
+}
+
+int server_start(short port) {
+  int listen_sock;
+  AssertFatal((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
+  int enable = 1;
+  AssertFatal(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
+  struct sockaddr_in addr = {
+sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
+  };
+  bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
+  AssertFatal(listen(listen_sock, 5) == 0, "");
+  return accept(listen_sock,NULL,NULL);
+}
+
+int client_start(char *IP, short port) {
+  int sock;
+  AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
+  struct sockaddr_in addr = {
+sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
+  };
+  addr.sin_addr.s_addr = inet_addr(IP);
+  bool connected=false;
+
+  while(!connected) {
+    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", IP, port);
+
+    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+      LOG_I(HW,"rfsimulator: connection established\n");
+      connected=true;
+    }
+
+    perror("simulated node");
+    sleep(1);
+  }
+
+  return sock;
+}
+
+enum  blocking_t {
+  notBlocking,
+  blocking
+};
+
+void setblocking(int sock, enum blocking_t active) {
+  int opts;
+  AssertFatal( (opts = fcntl(sock, F_GETFL)) >= 0,"");
+
+  if (active==blocking)
+    opts = opts & ~O_NONBLOCK;
+  else
+    opts = opts | O_NONBLOCK;
+
+  AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
+}
+
+int main(int argc, char *argv[]) {
+  if(argc != 4) {
+    printf("Need parameters: source file, server or destination IP, TCP port\n");
+    exit(1);
+  }
+
+  int fd;
+  AssertFatal((fd=open(argv[1],O_RDONLY)) != -1, "file: %s", argv[1]);
+  off_t fileSize=lseek(fd, 0, SEEK_END);
+  int serviceSock;
+
+  if (strcmp(argv[2],"server")==0) {
+    serviceSock=server_start(atoi(argv[3]));
+  } else {
+    client_start(argv[2],atoi(argv[3]));
+  }
+
+  samplesBlockHeader_t header;
+  int bufSize=100000;
+  void *buff=malloc(bufSize);
+
+  while (1) {
+    //Rewind the file to loop on the samples
+    if ( lseek(fd, 0, SEEK_CUR) >= fileSize )
+      lseek(fd, 0, SEEK_SET);
+
+    // Read one block and send it
+    setblocking(serviceSock, blocking);
+    AssertFatal(read(fd,&header,sizeof(header)), "");
+    fullwrite(serviceSock, &header, sizeof(header));
+    int dataSize=sizeof(sample_t)*header.size*header.nbAnt;
+
+    if (dataSize>bufSize)
+      buff=realloc(buff,dataSize);
+
+    AssertFatal(read(fd,buff,dataSize) == dataSize, "");
+    fullwrite(serviceSock, buff, dataSize);
+    // Purge incoming samples
+    setblocking(serviceSock, notBlocking);
+
+    while(recv(serviceSock,buff, bufSize, MSG_DONTWAIT) > 0) {
+    }
+  }
+
+  return 0;
+}
+
diff --git a/targets/RT/USER/lte-softmodem-common.c b/targets/RT/USER/lte-softmodem-common.c
index f152e7c83dc7ff44ded52925883a7ac686121c47..3413d6322cce97de9d1ea96f526f09ffee53ba61 100644
--- a/targets/RT/USER/lte-softmodem-common.c
+++ b/targets/RT/USER/lte-softmodem-common.c
@@ -37,6 +37,7 @@
 static softmodem_params_t softmodem_params;
 char *parallel_config=NULL;
 char *worker_config=NULL;
+double snr_dB=25;
 
 uint64_t get_softmodem_optmask(void) {
   return softmodem_params.optmask;
diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h
index e25cbed0b72e3fe723eaafa7914f77d6c9dd1637..f44dd39d4dcd5c51cb6a42c77405ca6f6688b900 100644
--- a/targets/RT/USER/lte-softmodem.h
+++ b/targets/RT/USER/lte-softmodem.h
@@ -150,7 +150,6 @@
     {"usrp-clksrc",                CONFIG_HLP_USRP_CLK_SRC,0,               strptr:(char **)&usrp_clksrc,       defstrval:"internal", TYPE_STRING,   0},   \
     {"mmapped-dma",                CONFIG_HLP_DMAMAP,      PARAMFLAG_BOOL,  uptr:&mmapped_dma,                  defintval:0,          TYPE_INT,      0},   \
     {"clock",                      CONFIG_HLP_CLK,         0,               uptr:&clock_source,                 defintval:0,          TYPE_UINT,     0},   \
-    {"s" ,                         CONFIG_HLP_SNR,         0,               iptr:&snr_dB,                       defintval:25,         TYPE_INT,      0},   \
     {"T" ,                         CONFIG_HLP_TDD,         PARAMFLAG_BOOL,  iptr:&tddflag,                      defintval:0,          TYPE_INT,      0},   \
     {"A",                          CONFIG_HLP_TADV,        0,               iptr:&(timingadv),                  defintval:0,          TYPE_INT,      0}    \
   }
@@ -197,6 +196,7 @@
     {"d" ,                      CONFIG_HLP_SOFTS,       PARAMFLAG_BOOL,         uptr:(uint32_t *)&do_forms,         defintval:0,                    TYPE_INT8,      0},                     \
     {"q" ,                      CONFIG_HLP_STMON,       PARAMFLAG_BOOL,         iptr:&opp_enabled,                  defintval:0,                    TYPE_INT,       0},                     \
     {"S" ,                      CONFIG_HLP_MSLOTS,      PARAMFLAG_BOOL,         u8ptr:&exit_missed_slots,           defintval:1,                    TYPE_UINT8,     0},                     \
+    {"s" ,                         CONFIG_HLP_SNR,         0,               dblptr:&snr_dB,                       defdblval:25,         TYPE_DOUBLE,      0},   \
     {"numerology" ,             CONFIG_HLP_NUMEROLOGY,  PARAMFLAG_BOOL,         iptr:&NUMEROLOGY,                   defintval:0,                    TYPE_INT,       0},                     \
     {"parallel-config",         CONFIG_HLP_PARALLEL_CMD,0,                      strptr:(char **)&parallel_config,   defstrval:NULL,                 TYPE_STRING,    0},                     \
     {"worker-config",           CONFIG_HLP_WORKER_CMD,  0,                      strptr:(char **)&worker_config,     defstrval:NULL,                 TYPE_STRING,    0},                     \
@@ -277,6 +277,7 @@ uint64_t get_pdcp_optmask(void);
 extern pthread_cond_t sync_cond;
 extern pthread_mutex_t sync_mutex;
 extern int sync_var;
+extern double snr_dB;
 
 
 extern uint32_t          downlink_frequency[MAX_NUM_CCs][4];
diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c
index 74380913dd629a405cd2dc08095c4bdbfec0e882..dd9eee7077a005b1be2bcb01fe7d4a6f96d5895c 100644
--- a/targets/RT/USER/lte-uesoftmodem.c
+++ b/targets/RT/USER/lte-uesoftmodem.c
@@ -131,7 +131,6 @@ int32_t                  uplink_frequency_offset[MAX_NUM_CCs][4];
 int UE_scan = 1;
 int UE_scan_carrier = 0;
 
-int snr_dB=25;
 
 runmode_t mode = normal_txrx;
 
@@ -810,7 +809,7 @@ int main( int argc, char **argv ) {
   //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX;
 
   if (IS_SOFTMODEM_SIML1 )  {
-    init_ocm((double)snr_dB,0);
+    init_ocm(snr_dB,0);
     PHY_vars_UE_g[0][0]->no_timing_correction = 1;
   }