diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index c23b0d1a91471d406910790e3c54dddb42dbc9d3..67cc6cfc3a33e7950d88c432817bae1927f526fe 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1518,7 +1518,7 @@ if (${RF_BOARD} STREQUAL "OAI_USRP")
   include_directories(${LIBBOOST_INCLUDE_DIR})
 endif (${RF_BOARD} STREQUAL "OAI_USRP")
 
-pkg_search_module(OPENPGM openpgm-5.1)
+pkg_search_module(OPENPGM openpgm-5.1 openpgm-5.2)
 if(NOT ${OPENPGM_FOUND})
   message("PACKAGE openpgm-5.1 is required by binaries such as oaisim: will fail later if this target is built")
 else()
@@ -1625,7 +1625,7 @@ add_executable(lte-softmodem
   ${T_SOURCE}
   )
 
-target_link_libraries (lte-softmodem
+target_link_libraries (lte-softmodem -ldl
   -Wl,--start-group
   RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} 
   -Wl,--end-group )
@@ -1652,8 +1652,8 @@ add_executable(lte-softmodem-nos1
   ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
   ${OPENAIR_TARGETS}/COMMON/create_tasks.c
   ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
-  #${OPENAIR2_DIR}/RRC/NAS/nas_config.c # enable if you want rrc to mount ip interface
-  #${OPENAIR2_DIR}/RRC/NAS/rb_config.c
+  ${OPENAIR2_DIR}/RRC/NAS/nas_config.c
+  ${OPENAIR2_DIR}/RRC/NAS/rb_config.c
   ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
   ${HW_SOURCE}
   ${TRANSPORT_SOURCE}  
@@ -1929,6 +1929,11 @@ foreach( d ${DirDefs} )
     list(APPEND itti_compiler_options "-I${d}")
 endforeach()
 
+# castxml doesn't work with c11 (gcc 5 default)
+# force castxml and clang compilation with gnu89 standard
+# we can't use cXX standard as pthread_rwlock_t is gnu standard
+list(APPEND itti_compiler_options "-std=gnu89")
+
 set (ITTI_H ${ITTI_DIR}/intertask_interface_types.h)
 add_custom_command (
   OUTPUT ${OPENAIR_BIN_DIR}/messages.xml
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index d1306b804b3073f35c7b30a2bf8d15fbdc816793..04289a83fa0c1b23f233b1aac01e24295cb6e0b1 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -33,6 +33,7 @@
 # brief OAI automated build tool that can be used to install, compile, run OAI.
 # author  Navid Nikaein, Lionel GAUTHIER, Laurent Thomas
 
+set -e
 
 ################################
 # include helper functions
@@ -59,6 +60,7 @@ RUN_GROUP=0
 TEST_CASE_GROUP=""
 BUILD_DOXYGEN=0
 T_TRACER="False"
+DISABLE_HARDWARE_DEPENDENCY="False"
 trap handle_ctrl_c INT
 
 function print_help() {
@@ -131,6 +133,8 @@ Options
    Disables CPU Affinity between UHD/TX/RX Threads (Valid only when deadline scheduler is disabled). By defaulT, CPU Affinity is enabled when not using deadline scheduler. It is enabled only with >2 CPUs. For eNB, CPU_0-> Device library (UHD), CPU_1->TX Threads, CPU_2...CPU_MAX->Rx Threads. For UE, CPU_0->Device Library(UHD), CPU_1..CPU_MAX -> All the UE threads
 --T-tracer
    Enables the T tracer.
+--disable-hardware-dependency
+   Disable HW dependency during installation
 Usage (first build):
  oaisim (eNB + UE): ./build_oai -I -g --oaisim -x --install-system-files
  Eurecom EXMIMO + COTS UE : ./build_oai -I -g --eNB -x --install-system-files
@@ -277,6 +281,10 @@ function main() {
             T_TRACER="True"
             echo_info "Enabling the T tracer"
             shift 1;;
+       --disable-hardware-dependency)
+            echo_info "Disabling hardware dependency for compiling software"
+            DISABLE_HARDWARE_DEPENDENCY="True"
+            shift 1;;
         -h | --help)
             print_help
             exit 1;;
@@ -386,10 +394,16 @@ function main() {
     if [ "$HW" == "OAI_USRP" ] ; then
       echo_info "installing packages for USRP support"
       check_install_usrp_uhd_driver
+      if [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then
+        install_usrp_uhd_driver
+      fi
     fi 
     if [ "$HW" == "OAI_BLADERF" ] ; then
       echo_info "installing packages for BLADERF support"
       check_install_bladerf_driver
+      if [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then
+        flash_firmware_bladerf
+      fi
     fi
   fi
 
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index 673ed190f03c4368ff7dd445fe37e38954081593..ac8d9f34c1541b115adae88a66e022a1bb8a7eca 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -67,7 +67,45 @@ echo_warning() { cecho "$*" $yellow       ;}
 echo_success() { cecho "$*" $green        ;}
 echo_info()    { cecho "$*" $blue         ;}
 
+########################
+# distribution helpers #
+########################
+
+# This function return a string to identify the distribution we are running
+# If we can't check the distribution, it returns "Unknown"
+# This function return always true as exit code by design
+# Examples:
+#   Ubuntu16.04
+#   Debian8.5
+get_distribution_release() {
+    local distributor
+    if distributor=$(lsb_release -si 2>/dev/null) ; then
+        echo $distributor$(lsb_release -sr)
+    else
+        echo Unknown
+    fi
+}
+
+check_supported_distribution() {
+    local distribution=$(get_distribution_release)
+    case "$distribution" in
+        "Ubuntu16.04") return 0 ;;
+        "Ubuntu14.04") return 0 ;;
+    esac
+    return 1
+}
 
+##################
+# Error handlers #
+##################
+
+handler_EXIT() {
+	local exit_code=$?
+    [ "$exit_code" -eq 0 ] || echo_error "build have failed"
+	exit $exit_code
+}
+
+trap handler_EXIT EXIT
 
 ###########################
 # Cleaners
@@ -109,6 +147,7 @@ clean_all_files() {
 
 compilations() {
   cd $OPENAIR_DIR/cmake_targets/$1/build
+  set +e
   {
     rm -f $3
     if [ "$VERBOSE_COMPILE" == "1" ]; then
@@ -118,12 +157,14 @@ compilations() {
     fi
 
   } > $dlog/$2.$REL.txt 2>&1
+  set -e
   echo_info "Log file for compilation has been written to: $dlog/$2.$REL.txt"
   if [ -s $3 ] ; then
      cp $3 $4
      echo_success "$2 compiled"
   else
      echo_error "$2 compilation failed"
+     exit 1
   fi
 }
 
@@ -186,23 +227,36 @@ install_gnutls_from_source(){
 
 check_install_usrp_uhd_driver(){
         #first we remove old installation
-        $SUDO apt-get remove uhd libuhd-dev libuhd003 uhd-host -y
+        $SUDO apt-get remove -y uhd || true
+        $SUDO apt-get remove libuhd-dev libuhd003 uhd-host -y
         v=$(lsb_release -cs)
         $SUDO apt-add-repository --remove "deb http://files.ettus.com/binaries/uhd/repo/uhd/ubuntu/$v $v main"
         #The new USRP repository
         $SUDO add-apt-repository ppa:ettusresearch/uhd -y
         $SUDO apt-get update
         $SUDO apt-get -y install  python python-tk libboost-all-dev libusb-1.0-0-dev
-        $SUDO apt-get -y install libuhd-dev libuhd003 uhd-host
+        $SUDO apt-get -y install libuhd-dev libuhd003
+}
+
+install_usrp_uhd_driver() {
+        # We move uhd-host apart because it depends on linux kernel version
+        # On newer kernels, it fails to install
+        $SUDO apt-get -y install uhd-host
         $SUDO uhd_images_downloader 
 }
+
 check_install_bladerf_driver(){
-	$SUDO add-apt-repository -y ppa:bladerf/bladerf
-	$SUDO apt-get update
+	if [ "$(get_distribution_release)" == "Ubuntu14.04" ] ; then
+		$SUDO add-apt-repository -y ppa:bladerf/bladerf
+		$SUDO apt-get update
+	fi
 	$SUDO apt-get install -y bladerf libbladerf-dev
 	$SUDO apt-get install -y bladerf-firmware-fx3
 	$SUDO apt-get install -y bladerf-fpga-hostedx40	
-	$SUDO bladeRF-cli --flash-firmware /usr/share/Nuand/bladeRF/bladeRF_fw.img	
+}
+
+flash_firmware_bladerf() {
+	$SUDO bladeRF-cli --flash-firmware /usr/share/Nuand/bladeRF/bladeRF_fw.img
 }
 
 check_install_additional_tools (){
@@ -228,12 +282,15 @@ check_install_additional_tools (){
 	ctags \
         ntpdate \
         iperf3 \
-        android-tools-adb
+        android-tools-adb \
+	wvdial \
+        python-numpy \
+    sshpass
 
     $SUDO pip install paramiko
     $SUDO pip install pyroute2
     $SUDO rm -fr /opt/ssh
-    $SUDO git clone https://gist.github.com/2190472.git /opt/ssh
+    $SUDO GIT_SSL_NO_VERIFY=true git clone https://gist.github.com/2190472.git /opt/ssh
     
     log_netiface=$OPENAIR_DIR/cmake_targets/log/netiface_install_log.txt
     echo_info "Installing Netinterfaces package. The logfile for installation is in $log_netiface"
@@ -248,8 +305,26 @@ check_install_additional_tools (){
 }
 
 check_install_oai_software() {
+    local specific_packages=""
+    if ! check_supported_distribution; then
+        echo_error "Your distribution $(get_distribution_release) is not supported by oai !"
+        exit 1
+    fi
     $SUDO apt-get update
+    $SUDO apt install -y software-properties-common
+    case "$(get_distribution_release)" in
+        "Ubuntu14.04")
+            specific_packages="libtasn1-3-dev"
+            # For iperf3
+            $SUDO add-apt-repository "deb http://archive.ubuntu.com/ubuntu trusty-backports universe"
+            $SUDO apt-get update
+            ;;
+        "Ubuntu16.04")
+            specific_packages="libtasn1-6-dev"
+            ;;
+    esac
     $SUDO apt-get install -y \
+    $specific_packages \
 	autoconf  \
 	automake  \
 	bison  \
@@ -273,9 +348,9 @@ check_install_oai_software() {
 	iptables-dev \
 	libatlas-base-dev \
 	libatlas-dev \
-	libblas3gf \
 	libblas-dev \
 	libconfig8-dev \
+	libffi-dev \
 	libforms-bin \
 	libforms-dev \
 	libgcrypt11-dev \
@@ -285,16 +360,16 @@ check_install_oai_software() {
 	libidn11-dev \
 	libmysqlclient-dev  \
 	liboctave-dev \
-	libpgm-5.1 \
 	libpgm-dev \
+	libpython2.7-dev \
 	libsctp1  \
 	libsctp-dev  \
 	libssl-dev  \
-	libtasn1-3-dev  \
 	libtool  \
 	libusb-1.0-0-dev \
 	libxml2 \
 	libxml2-dev  \
+	libxslt1-dev \
 	linux-headers-`uname -r` \
 	mscgen  \
 	octave \
@@ -307,11 +382,7 @@ check_install_oai_software() {
 	xmlstarlet \
 	python-pip \
 	pydb \
-	wvdial \
-        python-numpy \
-        sshpass \
-        libxslt1-dev \
-        android-tools-adb
+	wget
 
     $SUDO update-alternatives --set liblapack.so /usr/lib/atlas-base/atlas/liblapack.so
     
@@ -337,6 +408,7 @@ install_asn1c_from_source(){
     ./configure
     make -j`nproc`
     $SUDO make install
+    cd -
     ) > $asn1_install_log 2>&1
 }
 
diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a52d9a36677c9d9d15f873b7f0f874248b55c86c
--- /dev/null
+++ b/common/utils/T/.gitignore
@@ -0,0 +1,12 @@
+*.o
+*.a
+T_IDs.h
+T_messages.txt.h
+genids
+tracer/enb
+tracer/extract_config
+tracer/record
+tracer/replay
+tracer/textlog
+tracer/vcd
+tracee/tracee
diff --git a/common/utils/T/T.c b/common/utils/T/T.c
index 786b3722ed21c98b2734a126b077ed42a3f2295c..5d84afa6607f897329b0c71858014dca08f42f36 100644
--- a/common/utils/T/T.c
+++ b/common/utils/T/T.c
@@ -1,5 +1,4 @@
 #include "T.h"
-#include "T_messages.txt.h"
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -108,19 +107,17 @@ static void monitor_and_kill(int child1, int child2)
   exit(0);
 }
 
-void T_init(int remote_port, int wait_for_tracer)
+void T_init(int remote_port, int wait_for_tracer, int dont_fork)
 {
   int socket_pair[2];
   int s;
   int T_shm_fd;
-  unsigned char *buf;
-  int len;
   int child1, child2;
 
   if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
     { perror("socketpair"); abort(); }
 
-  /* child1 runs the local tracer and child2 runs the tracee */
+  /* child1 runs the local tracer and child2 (or main) runs the tracee */
 
   child1 = fork(); if (child1 == -1) abort();
   if (child1 == 0) {
@@ -130,10 +127,12 @@ void T_init(int remote_port, int wait_for_tracer)
   }
   close(socket_pair[0]);
 
-  child2 = fork(); if (child2 == -1) abort();
-  if (child2 != 0) {
-    close(socket_pair[1]);
-    monitor_and_kill(child1, child2);
+  if (dont_fork == 0) {
+    child2 = fork(); if (child2 == -1) abort();
+    if (child2 != 0) {
+      close(socket_pair[1]);
+      monitor_and_kill(child1, child2);
+    }
   }
 
   s = socket_pair[1];
@@ -153,29 +152,4 @@ void T_init(int remote_port, int wait_for_tracer)
   close(T_shm_fd);
 
   new_thread(T_receive_thread, NULL);
-
-  /* trace T_message.txt
-   * Send several messages -1 with content followed by message -2.
-   * We can't use the T macro directly, events -1 and -2 are special.
-   */
-  buf = T_messages_txt;
-  len = T_messages_txt_len;
-  while (len) {
-    int send_size = len;
-    if (send_size > T_PAYLOAD_MAXSIZE - sizeof(int))
-      send_size = T_PAYLOAD_MAXSIZE - sizeof(int);
-    do {
-      T_LOCAL_DATA
-      T_HEADER(T_ID(-1));
-      T_PUT_buffer(1, ((T_buffer){addr:(buf), length:(len)}));
-      T_COMMIT();
-    } while (0);
-    buf += send_size;
-    len -= send_size;
-  }
-  do {
-    T_LOCAL_DATA
-    T_HEADER(T_ID(-2));
-    T_COMMIT();
-  } while (0);
 }
diff --git a/common/utils/T/T.h b/common/utils/T/T.h
index a5aacb4b4f8e7ba121eb29078992e9a890740829..819615131e77cc72cf36d1f060ad61b8d1f8e2d2 100644
--- a/common/utils/T/T.h
+++ b/common/utils/T/T.h
@@ -562,7 +562,7 @@ extern T_cache_t *T_cache;
 
 extern int *T_active;
 
-void T_init(int remote_port, int wait_for_tracer);
+void T_init(int remote_port, int wait_for_tracer, int dont_fork);
 
 #else /* T_TRACER */
 
diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt
index 5678b588ba5c649f2e7d9c5ded9d76a466ce3868..05c08085c62558544725b4ad4580c663f17c9de0 100644
--- a/common/utils/T/T_messages.txt
+++ b/common/utils/T/T_messages.txt
@@ -52,7 +52,7 @@ ID = ENB_PHY_UL_CHANNEL_ESTIMATE
 ID = ENB_PHY_PUSCH_IQ
     DESC = eNodeB PUSCH received IQ data
     GROUP = ALL:PHY:GRAPHIC:HEAVY:ENB
-    FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,nb_rb : buffer,pusch_comp
+    FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,nb_rb : int,N_RB_UL : int,symbols_per_tti : buffer,pusch_comp
 ID = ENB_PHY_PUCCH_1AB_IQ
     DESC = eNodeB PUCCH received IQ data
     GROUP = ALL:PHY:GRAPHIC:HEAVY:ENB
@@ -79,10 +79,18 @@ ID = ENB_MAC_UE_UL_PDU
     DESC = MAC uplink UE received PDU
     GROUP = ALL:MAC:ENB
     FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,harq_pid : int,sdu_length : int,num_ce : int,num_sdu
+ID = ENB_MAC_UE_UL_PDU_WITH_DATA
+    DESC = MAC uplink UE received PDU
+    GROUP = ALL:MAC:ENB:HEAVY
+    FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,harq_pid : int,sdu_length : int,num_ce : int,num_sdu : buffer,data
 ID = ENB_MAC_UE_UL_SDU
     DESC = MAC uplink UE received SDU
     GROUP = ALL:MAC:ENB
     FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,lcid : int,length
+ID = ENB_MAC_UE_UL_SDU_WITH_DATA
+    DESC = MAC uplink UE received SDU
+    GROUP = ALL:MAC:ENB:HEAVY
+    FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,lcid : int,length : buffer,data
 ID = ENB_MAC_UE_UL_CE
     DESC = MAC uplink UE received control element
     GROUP = ALL:MAC:ENB
diff --git a/common/utils/T/local_tracer.c b/common/utils/T/local_tracer.c
index 93a56a9e3d41aa2ecd8f41aa617fe55c292c055e..68a937a6b56e80fe90d8a3ea27fc8cf3123af145 100644
--- a/common/utils/T/local_tracer.c
+++ b/common/utils/T/local_tracer.c
@@ -11,10 +11,12 @@
 #include <inttypes.h>
 #include <signal.h>
 
+#include "T.h"
+#include "T_messages.txt.h"
 #include "T_defs.h"
 #include "T_IDs.h"
 
-static T_cache_t *T_cache;
+static T_cache_t *T_local_cache;
 static int T_busylist_head;
 
 typedef struct databuf {
@@ -85,6 +87,38 @@ static int get_connection(char *addr, int port)
   return t;
 }
 
+static void forward(void *_forwarder, char *buf, int size);
+
+void send_T_messages_txt(void *forwarder)
+{
+  char buf[T_BUFFER_MAX];
+  char *T_LOCAL_buf = buf;
+  int T_LOCAL_size;
+  unsigned char *src;
+  int src_len;
+
+  /* trace T_message.txt
+   * Send several messages -1 with content followed by message -2.
+   */
+  src = T_messages_txt;
+  src_len = T_messages_txt_len;
+  while (src_len) {
+    int send_size = src_len;
+    if (send_size > T_PAYLOAD_MAXSIZE - sizeof(int))
+      send_size = T_PAYLOAD_MAXSIZE - sizeof(int);
+    /* TODO: be careful, we use internal T stuff, to rewrite? */
+    T_LOCAL_size = 0;
+    T_HEADER(T_ID(-1));
+    T_PUT_buffer(1, ((T_buffer){addr:(src), length:(send_size)}));
+    forward(forwarder, buf, T_LOCAL_size);
+    src += send_size;
+    src_len -= send_size;
+  }
+  T_LOCAL_size = 0;
+  T_HEADER(T_ID(-2));
+  forward(forwarder, buf, T_LOCAL_size);
+}
+
 /****************************************************************************/
 /*                      forward functions                                   */
 /****************************************************************************/
@@ -213,6 +247,7 @@ dead:
 
   close(f->socket_remote);
   f->socket_remote = get_connection("0.0.0.0", f->remote_port);
+  send_T_messages_txt(f);
   goto again;
 
   return NULL;
@@ -237,6 +272,7 @@ static void *forwarder(int port, int s)
 
   f->remote_port = port;
   f->socket_remote = get_connection("0.0.0.0", port);
+  send_T_messages_txt(f);
 
   new_thread(data_sender, f);
   new_thread(forward_remote_messages, f);
@@ -287,7 +323,7 @@ static void forward(void *_forwarder, char *buf, int size)
 
 static void wait_message(void)
 {
-  while (T_cache[T_busylist_head].busy == 0) usleep(1000);
+  while (T_local_cache[T_busylist_head].busy == 0) usleep(1000);
 }
 
 static void init_shm(void)
@@ -297,17 +333,17 @@ static void init_shm(void)
   if (s == -1) { perror(T_SHM_FILENAME); abort(); }
   if (ftruncate(s, T_CACHE_SIZE * sizeof(T_cache_t)))
     { perror(T_SHM_FILENAME); abort(); }
-  T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
-                 PROT_READ | PROT_WRITE, MAP_SHARED, s, 0);
-  if (T_cache == NULL)
+  T_local_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
+                       PROT_READ | PROT_WRITE, MAP_SHARED, s, 0);
+  if (T_local_cache == NULL)
     { perror(T_SHM_FILENAME); abort(); }
   close(s);
 
   /* let's garbage the memory to catch some potential problems
    * (think multiprocessor sync issues, barriers, etc.)
    */
-  memset(T_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
-  for (i = 0; i < T_CACHE_SIZE; i++) T_cache[i].busy = 0;
+  memset(T_local_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
+  for (i = 0; i < T_CACHE_SIZE; i++) T_local_cache[i].busy = 0;
 }
 
 void T_local_tracer_main(int remote_port, int wait_for_tracer,
@@ -335,9 +371,9 @@ void T_local_tracer_main(int remote_port, int wait_for_tracer,
   while (1) {
     wait_message();
     __sync_synchronize();
-    forward(f, T_cache[T_busylist_head].buffer,
-            T_cache[T_busylist_head].length);
-    T_cache[T_busylist_head].busy = 0;
+    forward(f, T_local_cache[T_busylist_head].buffer,
+            T_local_cache[T_busylist_head].length);
+    T_local_cache[T_busylist_head].busy = 0;
     T_busylist_head++;
     T_busylist_head &= T_CACHE_SIZE - 1;
   }
diff --git a/common/utils/T/tracee/Makefile b/common/utils/T/tracee/Makefile
index 703d49d029ae914638b0c1fd2ba7e56dbc349216..10ea3bdca3c80b8256c9b0601c0ed7f5439e5e6d 100644
--- a/common/utils/T/tracee/Makefile
+++ b/common/utils/T/tracee/Makefile
@@ -2,7 +2,7 @@ CC=gcc
 CFLAGS=-Wall -g -pthread -DT_TRACER -I.
 
 PROG=tracee
-OBJS=tracee.o ../T.o
+OBJS=tracee.o ../T.o ../local_tracer.o
 
 $(PROG): $(OBJS)
 	$(CC) $(CFLAGS) -o $(PROG) $(OBJS) -lrt
diff --git a/common/utils/T/tracee/tracee.c b/common/utils/T/tracee/tracee.c
index b4b73b9e67fa036e92def856a7328d5c197d4cb4..5f820ee42eecf5eb60fdb9669bf66cfa867db5df 100644
--- a/common/utils/T/tracee/tracee.c
+++ b/common/utils/T/tracee/tracee.c
@@ -6,7 +6,7 @@
 int main(void)
 {
   int frame = 0;
-  T_connect_to_tracer("127.0.0.1", 2020);
+  T_init(2021, 1, 0);
   while (1) {
     getchar();
     T(T_ENB_PHY_PUCCH_1AB_IQ, T_INT(0), T_INT(0), T_INT(frame), T_INT(0), T_INT(0), T_INT(0));
diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile
index bf0f72710cd04b4c4cb4a170a1a89fa51be5f2d8..ee289aae59636c629934de82eddbedf0932d832d 100644
--- a/common/utils/T/tracer/Makefile
+++ b/common/utils/T/tracer/Makefile
@@ -5,7 +5,16 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
 
 LIBS=-lX11 -lm -lpng -lXft
 
-all: textlog enb vcd
+all: record replay extract_config textlog enb vcd
+
+record: utils.o record.o database.o config.o
+	$(CC) $(CFLAGS) -o record $^ $(LIBS)
+
+replay: utils.o replay.o
+	$(CC) $(CFLAGS) -o replay $^ $(LIBS)
+
+extract_config: extract_config.o
+	$(CC) $(CFLAGS) -o extract_config $^ $(LIBS)
 
 textlog: utils.o textlog.o database.o event.o handler.o config.o \
          event_selector.o view/view.a gui/gui.a logger/logger.a \
@@ -40,8 +49,10 @@ filter/filter.a:
 	$(CC) $(CFLAGS) -c -o $@ $<
 
 clean:
-	rm -f *.o core tracer_remote textlog enb vcd
+	rm -f *.o core tracer_remote textlog enb vcd record replay
+	rm -f extract_config
 	cd gui && make clean
 	cd view && make clean
 	cd logger && make clean
 	cd filter && make clean
+	cd hacks && make clean
diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c
index f43e1d67077a0e4237210e0256b87bba18a0c494..b0ae285f6d0948e5d4fdcccfa93a86d3843d7090 100644
--- a/common/utils/T/tracer/enb.c
+++ b/common/utils/T/tracer/enb.c
@@ -33,9 +33,6 @@ typedef struct {
   pthread_mutex_t lock;
 } enb_data;
 
-#define DEFAULT_REMOTE_IP "127.0.0.1"
-#define DEFAULT_REMOTE_PORT 2021
-
 void is_on_changed(void *_d)
 {
   enb_data *d = _d;
@@ -116,8 +113,11 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database)
   widget *text;
   view *textview;
   int i;
+  widget *w;
+  view *v;
+  logger *l;
 
-  main_window = new_toplevel_window(g, 800, 600, "eNB tracer");
+  main_window = new_toplevel_window(g, 1200, 900, "eNB tracer");
   top_container = new_container(g, VERTICAL);
   widget_add_child(g, main_window, top_container, -1);
 
@@ -135,9 +135,39 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database)
    */
   framelog_set_skip(input_signal_log, 10);
   input_signal_view = new_view_xy(7680*10, 10,
-      g, input_signal_plot, new_color(g, "#0c0c72"));
+      g, input_signal_plot, new_color(g, "#0c0c72"), XY_LOOP_MODE);
   logger_add_view(input_signal_log, input_signal_view);
 
+  /* UE 0 PUSCH IQ data */
+  w = new_xy_plot(g, 55, 55, "PUSCH IQ", 50);
+  widget_add_child(g, line, w, -1);
+  xy_plot_set_range(g, w, -1000, 1000, -1000, 1000);
+  l = new_iqlog(h, database, "ENB_PHY_PUSCH_IQ", "nb_rb",
+      "N_RB_UL", "symbols_per_tti", "pusch_comp");
+  v = new_view_xy(100*12*14,10,g,w,new_color(g,"#000"),XY_FORCED_MODE);
+  logger_add_view(l, v);
+  logger_set_filter(l,
+      filter_eq(
+        filter_evarg(database, "ENB_PHY_PUSCH_IQ", "UE_ID"),
+        filter_int(0)
+      ));
+
+  /* UE 0 estimated UL channel */
+  w = new_xy_plot(g, 256*2, 55, "UL estimated channel", 50);
+  widget_add_child(g, line, w, -1);
+  xy_plot_set_range(g, w, 0, 512*10, -10, 80);
+  l = new_framelog(h, database,
+      "ENB_PHY_UL_CHANNEL_ESTIMATE", "subframe", "chest_t");
+  //framelog_set_skip(input_signal_log, 10);
+  framelog_set_update_only_at_sf9(l, 0);
+  v = new_view_xy(512*10, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE);
+  logger_add_view(l, v);
+  logger_set_filter(l,
+      filter_eq(
+        filter_evarg(database, "ENB_PHY_UL_CHANNEL_ESTIMATE", "UE_ID"),
+        filter_int(0)
+      ));
+
   /* downlink/uplink UE DCIs */
   widget_add_child(g, top_container,
       new_label(g,"DL/UL TICK/DCI/ACK/NACK "), -1);
@@ -440,14 +470,16 @@ int main(int n, char **v)
     logger *textlog;
     char *name, *desc;
     database_get_generic_description(database, i, &name, &desc);
-    if (strncmp(name, "LEGACY_", 7) != 0) continue;
-    textlog = new_textlog(h, database, name, desc);
-    logger_add_view(textlog, eg.legacy);
+    if (!strncmp(name, "LEGACY_", 7)) {
+      textlog = new_textlog(h, database, name, desc);
+      logger_add_view(textlog, eg.legacy);
+    }
     free(name);
     free(desc);
   }
 
   on_off(database, "ENB_PHY_INPUT_SIGNAL", is_on, 1);
+  on_off(database, "ENB_PHY_UL_CHANNEL_ESTIMATE", is_on, 1);
   on_off(database, "ENB_PHY_DL_TICK", is_on, 1);
   on_off(database, "ENB_PHY_DLSCH_UE_DCI", is_on, 1);
   on_off(database, "ENB_PHY_DLSCH_UE_ACK", is_on, 1);
@@ -458,6 +490,7 @@ int main(int n, char **v)
   on_off(database, "ENB_PHY_ULSCH_UE_ACK", is_on, 1);
   on_off(database, "ENB_PHY_ULSCH_UE_NACK", is_on, 1);
   on_off(database, "ENB_MASTER_TICK", is_on, 1);
+  on_off(database, "ENB_PHY_PUSCH_IQ", is_on, 1);
 
   on_off(database, "LEGACY_RRC_INFO", is_on, 1);
   on_off(database, "LEGACY_RRC_ERROR", is_on, 1);
@@ -477,7 +510,9 @@ int main(int n, char **v)
   view_add_log(eg.macview, "ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION",
       h, database, is_on);
   view_add_log(eg.macview, "ENB_MAC_UE_UL_PDU", h, database, is_on);
+  view_add_log(eg.macview, "ENB_MAC_UE_UL_PDU_WITH_DATA", h, database, is_on);
   view_add_log(eg.macview, "ENB_MAC_UE_UL_SDU", h, database, is_on);
+  view_add_log(eg.macview, "ENB_MAC_UE_UL_SDU_WITH_DATA", h, database, is_on);
   view_add_log(eg.macview, "ENB_MAC_UE_UL_CE", h, database, is_on);
 
   view_add_log(eg.rlcview, "ENB_RLC_DL", h, database, is_on);
@@ -545,6 +580,10 @@ int main(int n, char **v)
   view_add_log(eg.rrcview, "ENB_RRC_UNKNOW_MESSAGE",
       h, database, is_on);
 
+  /* deactivate those two by default, they are a bit heavy */
+  on_off(database, "ENB_MAC_UE_UL_SDU_WITH_DATA", is_on, 0);
+  on_off(database, "ENB_MAC_UE_UL_PDU_WITH_DATA", is_on, 0);
+
   for (i = 0; i < on_off_n; i++)
     on_off(database, on_off_name[i], is_on, on_off_action[i]);
 
diff --git a/common/utils/T/tracer/extract_config.c b/common/utils/T/tracer/extract_config.c
new file mode 100644
index 0000000000000000000000000000000000000000..f35d765cec5b3366b88eca9bd9bc85d2697a18e4
--- /dev/null
+++ b/common/utils/T/tracer/extract_config.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../T_defs.h"
+
+void usage(void)
+{
+  printf(
+"options:\n"
+"    -i <input file>           this option is mandatory\n"
+  );
+  exit(1);
+}
+
+#define ERR printf("ERROR: read file %s failed\n", input_filename)
+
+int main(int n, char **v)
+{
+  char *input_filename = NULL;
+  int i;
+  FILE *in;
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-i"))
+      { if (i > n-2) usage(); input_filename = v[++i]; continue; }
+    usage();
+  }
+
+  if (input_filename == NULL) {
+    printf("ERROR: provide an input file (-i)\n");
+    exit(1);
+  }
+
+  in = fopen(input_filename, "r");
+  if (in == NULL) { perror(input_filename); abort(); }
+
+  while (1) {
+    int type;
+    int32_t length;
+    char v[T_BUFFER_MAX];
+    int vpos = 0;
+
+    /* read event from file */
+    if (fread(&length, 4, 1, in) != 1) break;
+    memcpy(v+vpos, &length, 4);
+    vpos += 4;
+#ifdef T_SEND_TIME
+    if (length < sizeof(struct timespec)) { ERR; break; }
+    if (fread(v+vpos, sizeof(struct timespec), 1, in) != 1) { ERR; break; }
+    vpos += sizeof(struct timespec);
+    length -= sizeof(struct timespec);
+#endif
+    if (length < sizeof(int)) { ERR; break; }
+    if (fread(&type, sizeof(int), 1, in) != 1) { ERR; break; }
+    memcpy(v+vpos, &type, sizeof(int));
+    vpos += sizeof(int);
+    length -= sizeof(int);
+    if (length) if (fread(v+vpos, length, 1, in) != 1) { ERR; break; }
+    vpos += length;
+
+    if (type == -1) {
+      if (length < sizeof(int)) { ERR; break; }
+      length -= sizeof(int);
+      if (fwrite(v+vpos-length, length, 1, stdout) != 1) { ERR; break; }
+    }
+
+    /* TODO: parse all file? */
+    if (type == -2) break;
+  }
+
+  fclose(in);
+
+  return 0;
+}
diff --git a/common/utils/T/tracer/hacks/Makefile b/common/utils/T/tracer/hacks/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ab10305c0b356c7085695c9099d1fc93492330e9
--- /dev/null
+++ b/common/utils/T/tracer/hacks/Makefile
@@ -0,0 +1,18 @@
+CC=gcc
+CFLAGS=-Wall -g -pthread -DT_TRACER -I. -I..
+
+LIBS=-lX11 -lm -lpng -lXft
+
+all: dump_nack_signal
+
+dump_nack_signal: ../utils.o ../database.o ../config.o ../event.o \
+                  dump_nack_signal.o
+	$(CC) $(CFLAGS) -o dump_nack_signal $^ $(LIBS)
+
+.PHONY: all
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f *.o core dump_nack_signal
diff --git a/common/utils/T/tracer/hacks/dump_nack_signal.c b/common/utils/T/tracer/hacks/dump_nack_signal.c
new file mode 100644
index 0000000000000000000000000000000000000000..1627bdd14e925ad68797d16614be9e57bc23447e
--- /dev/null
+++ b/common/utils/T/tracer/hacks/dump_nack_signal.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "event.h"
+#include "database.h"
+#include "config.h"
+#include "../T_defs.h"
+
+void usage(void)
+{
+  printf(
+"options:\n"
+"    -d <database file>        this option is mandatory\n"
+"    -ip <host>                connect to given IP address (default %s)\n"
+"    -p <port>                 connect to given port (default %d)\n",
+  DEFAULT_REMOTE_IP,
+  DEFAULT_REMOTE_PORT
+  );
+  exit(1);
+}
+
+int main(int n, char **v)
+{
+  char *database_filename = NULL;
+  void *database;
+  char *ip = DEFAULT_REMOTE_IP;
+  int port = DEFAULT_REMOTE_PORT;
+  int i;
+  char t;
+  int number_of_events;
+  int socket;
+  int *is_on;
+  int ev_input, ev_nack;
+  int ev_ack;
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-d"))
+      { if (i > n-2) usage(); database_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
+    if (!strcmp(v[i], "-p"))
+      { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
+    usage();
+  }
+
+  if (database_filename == NULL) {
+    printf("ERROR: provide a database file (-d)\n");
+    exit(1);
+  }
+
+  database = parse_database(database_filename);
+
+  load_config_file(database_filename);
+
+  number_of_events = number_of_ids(database);
+  is_on = calloc(number_of_events, sizeof(int));
+  if (is_on == NULL) abort();
+
+  on_off(database, "ENB_PHY_INPUT_SIGNAL", is_on, 1);
+  on_off(database, "ENB_PHY_ULSCH_UE_NACK", is_on, 1);
+  on_off(database, "ENB_PHY_ULSCH_UE_ACK", is_on, 1);
+
+  ev_input = event_id_from_name(database, "ENB_PHY_INPUT_SIGNAL");
+  ev_nack = event_id_from_name(database, "ENB_PHY_ULSCH_UE_NACK");
+  ev_ack = event_id_from_name(database, "ENB_PHY_ULSCH_UE_ACK");
+
+  socket = connect_to(ip, port);
+
+  t = 1;
+  if (socket_send(socket, &t, 1) == -1 ||
+      socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
+      socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
+    abort();
+
+  char dump[10][T_BUFFER_MAX];
+  event dump_ev[10];
+FILE *z = fopen("/tmp/dd", "w"); if (z == NULL) abort();
+  while (1) {
+    char v[T_BUFFER_MAX];
+    event e;
+    e = get_event(socket, v, database);
+    if (e.type == -1) break;
+    if (e.type == ev_input) {
+      int sf = e.e[2].i;
+      memcpy(dump[sf], v, T_BUFFER_MAX);
+      dump_ev[sf] = e;
+      printf("input %d/%d\n", e.e[1].i, sf);
+if (fwrite(dump_ev[sf].e[4].b, dump_ev[sf].e[4].bsize, 1, z) != 1) abort();
+fflush(z);
+    }
+    if (e.type == ev_nack) {
+      int sf = e.e[2].i;
+      printf("nack %d/%d\n", e.e[1].i, sf);
+      FILE *f = fopen("/tmp/dump.raw", "w"); if (f == NULL) abort();
+      if (fwrite(dump[sf] + ((char *)dump_ev[sf].e[4].b - v),
+          dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
+      if (fclose(f)) abort();
+      printf("dumped... press enter (delta %d)\n", (int)((char *)dump_ev[sf].e[4].b - v));
+//      getchar();
+    }
+    if (e.type == ev_ack) {
+      int sf = e.e[2].i;
+      printf("ack %d/%d\n", e.e[1].i, sf);
+      FILE *f = fopen("/tmp/dump.raw", "w"); if (f == NULL) abort();
+      if (fwrite(dump[sf] + ((char *)dump_ev[sf].e[4].b - v),
+          dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
+      if (fclose(f)) abort();
+      printf("dumped... press enter (delta %d)\n", (int)((char *)dump_ev[sf].e[4].b - v));
+//      getchar();
+    }
+  }
+
+  return 0;
+}
diff --git a/common/utils/T/tracer/logger/Makefile b/common/utils/T/tracer/logger/Makefile
index e5391008380ccb32410dcc92a3a0788bd3ad8a45..8d23717a1329ba42cd5a156e47df673246ef13c3 100644
--- a/common/utils/T/tracer/logger/Makefile
+++ b/common/utils/T/tracer/logger/Makefile
@@ -1,7 +1,7 @@
 CC=gcc
 CFLAGS=-Wall -g -pthread -I..
 
-OBJS=logger.o textlog.o framelog.o ttilog.o timelog.o ticklog.o
+OBJS=logger.o textlog.o framelog.o ttilog.o timelog.o ticklog.o iqlog.o
 
 logger.a: $(OBJS)
 	ar cr logger.a $(OBJS)
diff --git a/common/utils/T/tracer/logger/framelog.c b/common/utils/T/tracer/logger/framelog.c
index 057960c38246b98b0e4c7be1225ec02dc9238495..45ae3e399f98dd4e1e091cf39606ad3b7ad3a88f 100644
--- a/common/utils/T/tracer/logger/framelog.c
+++ b/common/utils/T/tracer/logger/framelog.c
@@ -21,6 +21,7 @@ struct framelog {
                          */
   int skip_current;     /* internal data for the skip mechanism */
   int skip_on;          /* internal data for the skip mechanism */
+  int update_only_at_sf9;
 };
 
 static void _event(void *p, event e)
@@ -76,7 +77,7 @@ static void _event(void *p, event e)
     l->buffer[subframe * nsamples + i] = 10*log10(1.0+(float)(I*I+Q*Q));
   }
 
-  if (subframe == 9)
+  if (l->update_only_at_sf9 == 0 || subframe == 9)
     for (i = 0; i < l->common.vsize; i++)
       l->common.v[i]->append(l->common.v[i], l->x, l->buffer, l->blength);
 }
@@ -91,6 +92,8 @@ logger *new_framelog(event_handler *h, void *database,
 
   ret = calloc(1, sizeof(struct framelog)); if (ret == NULL) abort();
 
+  ret->update_only_at_sf9 = 1;
+
   ret->common.event_name = strdup(event_name);
   if (ret->common.event_name == NULL) abort();
   ret->database = database;
@@ -144,3 +147,9 @@ void framelog_set_skip(logger *_this, int skip_delay)
   l->skip_current = 0;
   l->skip_on = 0;
 }
+
+void framelog_set_update_only_at_sf9(logger *_this, int update_only_at_sf9)
+{
+  struct framelog *l = _this;
+  l->update_only_at_sf9 = update_only_at_sf9;
+}
diff --git a/common/utils/T/tracer/logger/iqlog.c b/common/utils/T/tracer/logger/iqlog.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d303607ac9f2faf9c0ddf91971495b1300c4e5c
--- /dev/null
+++ b/common/utils/T/tracer/logger/iqlog.c
@@ -0,0 +1,187 @@
+#include "logger.h"
+#include "logger_defs.h"
+#include "handler.h"
+#include "database.h"
+#include "filter/filter.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+struct iqlog {
+  struct logger common;
+  void *database;
+  int nb_rb_arg;
+  int N_RB_UL_arg;
+  int symbols_per_tti_arg;
+  int buffer_arg;
+  float *i;
+  float *q;
+  int max_length;
+};
+
+#if 0
+/* this function passes all received IQ samples to the views */
+static void _event(void *p, event e)
+{
+  struct iqlog *l = p;
+  int i;
+  void *buffer;
+  int bsize;
+  int nsamples;
+
+  if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
+    return;
+
+  buffer = e.e[l->buffer_arg].b;
+  bsize = e.e[l->buffer_arg].bsize;
+
+  nsamples = bsize / (2*sizeof(int16_t));
+
+  if (nsamples > l->max_length) {
+    l->i = realloc(l->i, nsamples * sizeof(float));
+    if (l->i == NULL) abort();
+    l->q = realloc(l->q, nsamples * sizeof(float));
+    if (l->q == NULL) abort();
+    l->max_length = nsamples;
+  }
+
+  for (i = 0; i < nsamples; i++) {
+    l->i[i] = ((int16_t *)buffer)[i*2];
+    l->q[i] = ((int16_t *)buffer)[i*2+1];
+  }
+
+  for (i = 0; i < l->common.vsize; i++)
+    l->common.v[i]->append(l->common.v[i], l->i, l->q, nsamples);
+}
+#endif
+
+static void _event(void *p, event e)
+{
+  struct iqlog *l = p;
+  int i, j;
+  void *buffer;
+  int bsize;
+  int nb_rb;
+  int N_RB_UL;
+  int symbols_per_tti;
+  int max_nsamples;
+  float *idst, *qdst;
+  int count;
+
+  if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
+    return;
+
+  nb_rb = e.e[l->nb_rb_arg].i;
+  N_RB_UL = e.e[l->N_RB_UL_arg].i;
+  symbols_per_tti = e.e[l->symbols_per_tti_arg].i;
+
+  buffer = e.e[l->buffer_arg].b;
+  bsize = e.e[l->buffer_arg].bsize;
+
+  if (bsize != N_RB_UL * symbols_per_tti * 12 * 4) {
+    printf("%s:%d:%s: bad buffer size\n", __FILE__, __LINE__, __FUNCTION__);
+    abort();
+  }
+
+  max_nsamples = bsize / 4;
+
+  if (max_nsamples > l->max_length) {
+    l->i = realloc(l->i, max_nsamples * sizeof(float));
+    if (l->i == NULL) abort();
+    l->q = realloc(l->q, max_nsamples * sizeof(float));
+    if (l->q == NULL) abort();
+    l->max_length = max_nsamples;
+  }
+
+  idst = l->i;
+  qdst = l->q;
+  count = 0;
+  for (i = 0; i < symbols_per_tti; i++)
+    for (j = 0; j < 12 * nb_rb; j++) {
+      *idst = ((int16_t *)buffer)[(i*N_RB_UL*12 + j) * 2];
+      *qdst = ((int16_t *)buffer)[(i*N_RB_UL*12 + j) * 2 + 1];
+      idst++;
+      qdst++;
+      count++;
+    }
+
+  for (i = 0; i < l->common.vsize; i++)
+    l->common.v[i]->append(l->common.v[i], l->i, l->q, count);
+}
+
+logger *new_iqlog(event_handler *h, void *database,
+    char *event_name, char *nb_rb, char *N_RB_UL, char *symbols_per_tti,
+    char *buffer_varname)
+{
+  struct iqlog *ret;
+  int event_id;
+  database_event_format f;
+  int i;
+
+  ret = calloc(1, sizeof(struct iqlog)); if (ret == NULL) abort();
+
+  ret->common.event_name = strdup(event_name);
+  if (ret->common.event_name == NULL) abort();
+  ret->database = database;
+
+  event_id = event_id_from_name(database, event_name);
+
+  ret->common.handler_id = register_handler_function(h,event_id,_event,ret);
+
+  f = get_format(database, event_id);
+
+  /* look for args */
+  ret->nb_rb_arg = -1;
+  ret->N_RB_UL_arg = -1;
+  ret->symbols_per_tti_arg = -1;
+  ret->buffer_arg = -1;
+  for (i = 0; i < f.count; i++) {
+    if (!strcmp(f.name[i], nb_rb)) ret->nb_rb_arg = i;
+    if (!strcmp(f.name[i], N_RB_UL)) ret->N_RB_UL_arg = i;
+    if (!strcmp(f.name[i], symbols_per_tti)) ret->symbols_per_tti_arg = i;
+    if (!strcmp(f.name[i], buffer_varname)) ret->buffer_arg = i;
+  }
+  if (ret->nb_rb_arg == -1) {
+    printf("%s:%d: argument '%s' not found in event '%s'\n",
+        __FILE__, __LINE__, nb_rb, event_name);
+    abort();
+  }
+  if (ret->N_RB_UL_arg == -1) {
+    printf("%s:%d: argument '%s' not found in event '%s'\n",
+        __FILE__, __LINE__, N_RB_UL, event_name);
+    abort();
+  }
+  if (ret->symbols_per_tti_arg == -1) {
+    printf("%s:%d: argument '%s' not found in event '%s'\n",
+        __FILE__, __LINE__, symbols_per_tti, event_name);
+    abort();
+  }
+  if (ret->buffer_arg == -1) {
+    printf("%s:%d: buffer argument '%s' not found in event '%s'\n",
+        __FILE__, __LINE__, buffer_varname, event_name);
+    abort();
+  }
+  if (strcmp(f.type[ret->nb_rb_arg], "int") != 0) {
+    printf("%s:%d: argument '%s' has wrong type (should be 'int')\n",
+        __FILE__, __LINE__, nb_rb);
+    abort();
+  }
+  if (strcmp(f.type[ret->N_RB_UL_arg], "int") != 0) {
+    printf("%s:%d: argument '%s' has wrong type (should be 'int')\n",
+        __FILE__, __LINE__, nb_rb);
+    abort();
+  }
+  if (strcmp(f.type[ret->symbols_per_tti_arg], "int") != 0) {
+    printf("%s:%d: argument '%s' has wrong type (should be 'int')\n",
+        __FILE__, __LINE__, symbols_per_tti);
+    abort();
+  }
+  if (strcmp(f.type[ret->buffer_arg], "buffer") != 0) {
+    printf("%s:%d: argument '%s' has wrong type (should be 'buffer')\n",
+        __FILE__, __LINE__, buffer_varname);
+    abort();
+  }
+
+  return ret;
+}
diff --git a/common/utils/T/tracer/logger/logger.h b/common/utils/T/tracer/logger/logger.h
index e3e4b97aa5e4e85844376c61663036d3f7a78b5b..a777581db91e513509a5abb0ebed9cfa359cc4e5 100644
--- a/common/utils/T/tracer/logger/logger.h
+++ b/common/utils/T/tracer/logger/logger.h
@@ -13,8 +13,14 @@ logger *new_ttilog(void *event_handler, void *database,
 logger *new_timelog(void *event_handler, void *database, char *event_name);
 logger *new_ticklog(void *event_handler, void *database,
     char *event_name, char *frame_name, char *subframe_name);
+logger *new_iqlog(void *event_handler, void *database,
+    char *event_name, char *nb_rb, char *N_RB_UL, char *symbols_per_tti,
+    char *buffer_varname);
 
 void framelog_set_skip(logger *_this, int skip_delay);
+void framelog_set_update_only_at_sf9(logger *_this, int update_only_at_sf9);
+
+void textlog_dump_buffer(logger *_this, int dump_buffer);
 
 #include "view/view.h"
 
diff --git a/common/utils/T/tracer/logger/textlog.c b/common/utils/T/tracer/logger/textlog.c
index e80af7813e014c5174a01b83853a58d55179cd7c..9eb6fd02d8fbbec5d63702c4b89d80df2327fe92 100644
--- a/common/utils/T/tracer/logger/textlog.c
+++ b/common/utils/T/tracer/logger/textlog.c
@@ -32,12 +32,13 @@ struct textlog {
   int fsize;
   /* local output buffer */
   OBUF o;
+  int dump_buffer;
 };
 
 static void _event(void *p, event e)
 {
   struct textlog *l = p;
-  int i;
+  int i, j;
 #ifdef T_SEND_TIME
   struct tm *t;
   char tt[64];
@@ -65,6 +66,14 @@ static void _event(void *p, event e)
   case BUFFER:
     PUTS(&l->o, "{buffer size:");
     PUTI(&l->o, e.e[l->f[i].event_arg].bsize);
+    if (l->dump_buffer) {
+      PUTS(&l->o, " [");
+      for (j = 0; j < e.e[l->f[i].event_arg].bsize; j++) {
+        PUTX2(&l->o, ((unsigned char *)e.e[l->f[i].event_arg].b)[j]);
+        PUTC(&l->o, ' ');
+      }
+      PUTS(&l->o, "]");
+    }
     PUTS(&l->o, "}");
     break;
   }
@@ -196,3 +205,13 @@ error:
   printf("%s:%d: bad format '%s'\n", __FILE__, __LINE__, format);
   abort();
 }
+
+/****************************************************************************/
+/*                             public functions                             */
+/****************************************************************************/
+
+void textlog_dump_buffer(logger *_this, int dump_buffer)
+{
+  struct textlog *l = _this;
+  l->dump_buffer = dump_buffer;
+}
diff --git a/common/utils/T/tracer/record.c b/common/utils/T/tracer/record.c
new file mode 100644
index 0000000000000000000000000000000000000000..c81b93e7d73b89c176462bd2cbde58d150ad2371
--- /dev/null
+++ b/common/utils/T/tracer/record.c
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include "database.h"
+#include "utils.h"
+#include "../T_defs.h"
+#include "config.h"
+
+void usage(void)
+{
+  printf(
+"options:\n"
+"    -d <database file>        this option is mandatory\n"
+"    -o <output file>          this option is mandatory\n"
+"    -on <GROUP or ID>         turn log ON for given GROUP or ID\n"
+"    -off <GROUP or ID>        turn log OFF for given GROUP or ID\n"
+"    -ON                       turn all logs ON\n"
+"    -OFF                      turn all logs OFF\n"
+"                              note: you may pass several -on/-off/-ON/-OFF,\n"
+"                                    they will be processed in order\n"
+"                                    by default, all is off\n"
+"    -ip <host>                connect to given IP address (default %s)\n"
+"    -p <port>                 connect to given port (default %d)\n",
+  DEFAULT_REMOTE_IP,
+  DEFAULT_REMOTE_PORT
+  );
+  exit(1);
+}
+
+volatile int run = 1;
+
+static int socket = -1;
+
+void force_stop(int x)
+{
+  printf("\ngently quit...\n");
+  close(socket);
+  socket = -1;
+  run = 0;
+}
+
+int main(int n, char **v)
+{
+  char *database_filename = NULL;
+  char *output_filename = NULL;
+  FILE *out;
+  void *database;
+  char *ip = DEFAULT_REMOTE_IP;
+  int port = DEFAULT_REMOTE_PORT;
+  char **on_off_name;
+  int *on_off_action;
+  int on_off_n = 0;
+  int *is_on;
+  int number_of_events;
+  int i;
+  char mt;
+
+  /* write on a socket fails if the other end is closed and we get SIGPIPE */
+  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
+
+  on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort();
+  on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort();
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-d"))
+      { if (i > n-2) usage(); database_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-o"))
+      { if (i > n-2) usage(); output_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
+    if (!strcmp(v[i], "-p"))
+      { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
+    if (!strcmp(v[i], "-on")) { if (i > n-2) usage();
+      on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; }
+    if (!strcmp(v[i], "-off")) { if (i > n-2) usage();
+      on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; }
+    if (!strcmp(v[i], "-ON"))
+      { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
+    if (!strcmp(v[i], "-OFF"))
+      { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
+    usage();
+  }
+
+  if (database_filename == NULL) {
+    printf("ERROR: provide a database file (-d)\n");
+    exit(1);
+  }
+  if (output_filename == NULL) {
+    printf("ERROR: provide an output file (-o)\n");
+    exit(1);
+  }
+
+  database = parse_database(database_filename);
+
+  load_config_file(database_filename);
+
+  number_of_events = number_of_ids(database);
+  is_on = calloc(number_of_events, sizeof(int));
+  if (is_on == NULL) abort();
+
+  for (i = 0; i < on_off_n; i++)
+    on_off(database, on_off_name[i], is_on, on_off_action[i]);
+
+  socket = connect_to(ip, port);
+
+  /* activate selected traces */
+  mt = 1;
+  if (socket_send(socket, &mt, 1) == -1 ||
+      socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
+      socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
+    abort();
+
+  out = fopen(output_filename, "w");
+  if (out == NULL) {
+    perror(output_filename);
+    exit(1);
+  }
+
+  /* exit on ctrl+c and ctrl+z */
+  if (signal(SIGQUIT, force_stop) == SIG_ERR) abort();
+  if (signal(SIGINT, force_stop) == SIG_ERR) abort();
+  if (signal(SIGTSTP, force_stop) == SIG_ERR) abort();
+
+  /* read messages */
+  while (run) {
+    int type;
+    int32_t length;
+    char v[T_BUFFER_MAX];
+    int vpos = 0;
+
+    if (fullread(socket, &length, 4) == -1) goto read_error;
+    memcpy(v+vpos, &length, 4);
+    vpos += 4;
+#ifdef T_SEND_TIME
+    if (fullread(socket,v+vpos,sizeof(struct timespec))==-1) goto read_error;
+    vpos += sizeof(struct timespec);
+    length -= sizeof(struct timespec);
+#endif
+    if (fullread(socket, &type, sizeof(int)) == -1) goto read_error;
+    memcpy(v+vpos, &type, sizeof(int));
+    vpos += sizeof(int);
+    length -= sizeof(int);
+    if (fullread(socket, v+vpos, length) == -1) goto read_error;
+    vpos += length;
+
+    if (type == -1) append_received_config_chunk(v+vpos-length, length);
+    if (type == -2) verify_config();
+
+    if (fwrite(v, vpos, 1, out) != 1) {
+      printf("error saving data to file %s\n", output_filename);
+      fclose(out);
+      exit(1);
+    }
+  }
+
+read_error:
+  fclose(out);
+
+  return 0;
+}
diff --git a/common/utils/T/tracer/replay.c b/common/utils/T/tracer/replay.c
new file mode 100644
index 0000000000000000000000000000000000000000..be7e8d60c69fefcdd562ec79c5dea01c384b92c0
--- /dev/null
+++ b/common/utils/T/tracer/replay.c
@@ -0,0 +1,183 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "utils.h"
+#include "../T_defs.h"
+
+#define DEFAULT_REMOTE_PORT 2021
+
+/* replay.c does not know anything about events - it just has the array
+ * is_on that grows each time replay.c sees a type that does not fit in
+ * there (the idea is to isolate replay.c as maximum by not using unneeded
+ * information)
+ */
+int *is_on;
+int is_on_size;
+
+/* this lock is used to protect access to is_on/is_on_size */
+pthread_mutex_t biglock = PTHREAD_MUTEX_INITIALIZER;
+
+void set_is_on_size(int size)
+{
+  is_on = realloc(is_on, size * sizeof(int)); if (is_on == NULL) abort();
+  memset(is_on + is_on_size, 0, (size - is_on_size) * sizeof(int));
+  is_on_size = size;
+}
+
+void lock(void)
+{
+  if (pthread_mutex_lock(&biglock)) abort();
+}
+
+void unlock(void)
+{
+  if (pthread_mutex_unlock(&biglock)) abort();
+}
+
+#define QUIT(x) do { printf("%s\n", x); exit(1); } while(0)
+
+void get_message(int s)
+{
+  char t;
+  int l;
+  int id;
+  int on;
+
+  if (read(s, &t, 1) != 1) QUIT("get_message fails");
+  lock();
+  switch (t) {
+  case 0:
+    /* toggle all those IDs */
+    if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
+    while (l) {
+      if (read(s, &id, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
+      if (id > is_on_size - 1) set_is_on_size(id + 1);
+      is_on[id] = 1 - is_on[id];
+      l--;
+    }
+    break;
+  case 1:
+    /* set IDs as given */
+    /* optimize? */
+    if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
+    if (l > is_on_size) set_is_on_size(l);
+    id = 0;
+    while (l) {
+      if (read(s, &on, sizeof(int)) != sizeof(int))
+        QUIT("get_message fails");
+      is_on[id] = on;
+      id++;
+      l--;
+    }
+    break;
+  case 2: break; /* do nothing, this message is to wait for local tracer */
+  default: abort();
+  }
+  unlock();
+}
+
+void *get_message_thread(void *_socket)
+{
+  int socket = *(int *)_socket;
+
+  while (1) get_message(socket);
+
+  return NULL;
+}
+
+void usage(void)
+{
+  printf(
+"options:\n"
+"    -i <input file>           this option is mandatory\n"
+"    -p <port>                 wait connection on given port (default %d)\n"
+"    -w                        user must press a key after each sent event\n",
+  DEFAULT_REMOTE_PORT
+  );
+  exit(1);
+}
+
+#define ERR printf("ERROR: read file %s failed\n", input_filename)
+
+int main(int n, char **v)
+{
+  int port = DEFAULT_REMOTE_PORT;
+  char *input_filename = NULL;
+  int i;
+  int socket;
+  FILE *in;
+  int do_send;
+  int do_wait = 0;
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-i"))
+      { if (i > n-2) usage(); input_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-p"))
+      { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
+    if (!strcmp(v[i], "-w")) { do_wait = 1; continue; }
+    usage();
+  }
+
+  if (input_filename == NULL) {
+    printf("ERROR: provide an input file (-i)\n");
+    exit(1);
+  }
+
+  in = fopen(input_filename, "r");
+  if (in == NULL) { perror(input_filename); abort(); }
+
+  socket = get_connection("0.0.0.0", port);
+
+  /* get first message to activate selected traces */
+  get_message(socket);
+
+  new_thread(get_message_thread, &socket);
+
+  while (1) {
+    int type;
+    int32_t length;
+    char v[T_BUFFER_MAX];
+    int vpos = 0;
+
+    /* read event from file */
+    if (fread(&length, 4, 1, in) != 1) break;
+    memcpy(v+vpos, &length, 4);
+    vpos += 4;
+#ifdef T_SEND_TIME
+    if (length < sizeof(struct timespec)) { ERR; break; }
+    if (fread(v+vpos, sizeof(struct timespec), 1, in) != 1) { ERR; break; }
+    vpos += sizeof(struct timespec);
+    length -= sizeof(struct timespec);
+#endif
+    if (length < sizeof(int)) { ERR; break; }
+    if (fread(&type, sizeof(int), 1, in) != 1) { ERR; break; }
+    memcpy(v+vpos, &type, sizeof(int));
+    vpos += sizeof(int);
+    length -= sizeof(int);
+    if (length) if (fread(v+vpos, length, 1, in) != 1) { ERR; break; }
+    vpos += length;
+
+    /* only send if configured to do so */
+    lock();
+    if (type < 0) do_send = 1;
+    else {
+      if (type > is_on_size - 1) set_is_on_size(type+1);
+      do_send = is_on[type];
+    }
+    unlock();
+
+    if (do_send)
+      if (socket_send(socket, v, vpos) != 0)
+        { printf("ERROR: socket writing failed\n"); abort(); }
+
+    if (do_send && do_wait) getchar();
+  }
+
+  fclose(in);
+  close(socket);
+
+  return 0;
+}
diff --git a/common/utils/T/tracer/textlog.c b/common/utils/T/tracer/textlog.c
index f11ca96bd9ea10fa29f573aac6395d94150322f4..32bf1ed791ce10060fb48b62d7f4b69c94b23ba9 100644
--- a/common/utils/T/tracer/textlog.c
+++ b/common/utils/T/tracer/textlog.c
@@ -14,9 +14,6 @@
 #include "event_selector.h"
 #include "config.h"
 
-#define DEFAULT_REMOTE_IP "127.0.0.1"
-#define DEFAULT_REMOTE_PORT 2021
-
 typedef struct {
   int socket;
   int *is_on;
@@ -55,6 +52,7 @@ void usage(void)
 "                              note: you may pass several -on/-off/-ON/-OFF,\n"
 "                                    they will be processed in order\n"
 "                                    by default, all is off\n"
+"    -full                     also dump buffers' content\n"
 "    -ip <host>                connect to given IP address (default %s)\n"
 "    -p <port>                 connect to given port (default %d)\n"
 "    -x                        GUI output\n"
@@ -93,6 +91,7 @@ int main(int n, char **v)
   view *out;
   int gui_active = 1;
   textlog_data textlog_data;
+  int full = 0;
 
   /* write on a socket fails if the other end is closed and we get SIGPIPE */
   if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
@@ -118,6 +117,7 @@ int main(int n, char **v)
     if (!strcmp(v[i], "-x")) { gui_mode = 1; continue; }
     if (!strcmp(v[i], "-debug-gui")) { gui_logd = 1; continue; }
     if (!strcmp(v[i], "-no-gui")) { gui_active = 0; continue; }
+    if (!strcmp(v[i], "-full")) { full = 1; continue; }
     usage();
   }
 
@@ -162,6 +162,7 @@ int main(int n, char **v)
 //        "ENB_PHY_UL_CHANNEL_ESTIMATE",
 //        "ev: {} eNB_id [eNB_ID] frame [frame] subframe [subframe]");
     logger_add_view(textlog, out);
+    if (full) textlog_dump_buffer(textlog, 1);
     free(name);
     free(desc);
   }
diff --git a/common/utils/T/tracer/utils.c b/common/utils/T/tracer/utils.c
index 3ebc000c671b62799c330775e0804e9ba8279d95..a22e0a0565dabecfa928d2bd6d4c7c5df6c72553 100644
--- a/common/utils/T/tracer/utils.c
+++ b/common/utils/T/tracer/utils.c
@@ -190,6 +190,13 @@ void PUTI(OBUF *o, int i)
   PUTS(o, s);
 }
 
+void PUTX2(OBUF *o, int i)
+{
+  char s[64];
+  sprintf(s, "%2.2x", i);
+  PUTS(o, s);
+}
+
 void PUTUL(OBUF *o, unsigned long l)
 {
   char s[128];
diff --git a/common/utils/T/tracer/utils.h b/common/utils/T/tracer/utils.h
index e15a8d2fbad5c6e910e3ba3e21c6b0cc219a9952..086e92b5dcb4cb0e2fd6476132a815b3b018ba6a 100644
--- a/common/utils/T/tracer/utils.h
+++ b/common/utils/T/tracer/utils.h
@@ -20,6 +20,9 @@ list *list_append(list *l, void *data);
 /* socket                                                                   */
 /****************************************************************************/
 
+#define DEFAULT_REMOTE_IP "127.0.0.1"
+#define DEFAULT_REMOTE_PORT 2021
+
 /* socket_send: return 0 if okay, -1 on error */
 int socket_send(int socket, void *buffer, int size);
 int get_connection(char *addr, int port);
@@ -41,6 +44,7 @@ void PUTC(OBUF *o, char c);
 void PUTS(OBUF *o, char *s);
 void PUTS_CLEAN(OBUF *o, char *s);
 void PUTI(OBUF *o, int i);
+void PUTX2(OBUF *o, int i);
 void PUTUL(OBUF *o, unsigned long i);
 
 #endif /* _UTILS_H_ */
diff --git a/common/utils/T/tracer/vcd.c b/common/utils/T/tracer/vcd.c
index 45aa4e26e2ae332586a143c1ebf680fcd34c9d1d..0ad2756c2a49d218314aa4b586ba6a7bac0765ab 100644
--- a/common/utils/T/tracer/vcd.c
+++ b/common/utils/T/tracer/vcd.c
@@ -40,9 +40,6 @@ no_connection:
   if (pthread_mutex_unlock(&d->lock)) abort();
 }
 
-#define DEFAULT_REMOTE_IP "127.0.0.1"
-#define DEFAULT_REMOTE_PORT 2021
-
 void usage(void)
 {
   printf(
diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h
index cbc5e21b73d95fb3b15524977663a6054846fc5f..2173c842ce956929945ef1e38662f64e90e0dcc2 100644
--- a/common/utils/T/tracer/view/view.h
+++ b/common/utils/T/tracer/view/view.h
@@ -11,10 +11,12 @@ typedef struct view {
   void (*set)(struct view *this, char *name, ...);
 } view;
 
+enum xy_mode { XY_LOOP_MODE, XY_FORCED_MODE };
+
 view *new_view_stdout(void);
 view *new_view_textlist(int maxsize, float refresh_rate, gui *g, widget *w);
 view *new_view_xy(int length, float refresh_rate, gui *g, widget *w,
-    int color);
+    int color, enum xy_mode mode);
 view *new_view_tti(float refresh_rate, gui *g, widget *w,
     int color);
 view *new_view_time(int number_of_seconds, float refresh_rate,
diff --git a/common/utils/T/tracer/view/xy.c b/common/utils/T/tracer/view/xy.c
index 1407a16a0e44614c8e86b05569712d738439cfc2..96a44cf5129e41f044cdbf559df32709fb5a8ff2 100644
--- a/common/utils/T/tracer/view/xy.c
+++ b/common/utils/T/tracer/view/xy.c
@@ -14,6 +14,7 @@ struct xy {
   float refresh_rate;
   pthread_mutex_t lock;
   int length;
+  int max_length;      /* used in XY_FORCED_MODE */
   float *x;
   float *y;
   int insert_point;
@@ -39,7 +40,7 @@ static void clear(view *this)
   /* TODO */
 }
 
-static void append(view *_this, float *x, float *y, int length)
+static void append_loop(view *_this, float *x, float *y, int length)
 {
   struct xy *this = (struct xy *)_this;
   int i;
@@ -61,6 +62,25 @@ static void append(view *_this, float *x, float *y, int length)
   if (pthread_mutex_unlock(&this->lock)) abort();
 }
 
+static void append_forced(view *_this, float *x, float *y, int length)
+{
+  struct xy *this = (struct xy *)_this;
+
+  if (length > this->max_length) {
+    printf("%s:%d:%s: bad length (%d), max allowed is %d\n",
+        __FILE__, __LINE__, __FUNCTION__, length, this->max_length);
+    abort();
+  }
+
+  if (pthread_mutex_lock(&this->lock)) abort();
+
+  memcpy(this->x, x, length * sizeof(float));
+  memcpy(this->y, y, length * sizeof(float));
+  this->length = length;
+
+  if (pthread_mutex_unlock(&this->lock)) abort();
+}
+
 static void set(view *_this, char *name, ...)
 {
   struct xy *this = (struct xy *)_this;
@@ -89,24 +109,35 @@ static void set(view *_this, char *name, ...)
 }
 
 view *new_view_xy(int length, float refresh_rate, gui *g, widget *w,
-    int color)
+    int color, enum xy_mode mode)
 {
   struct xy *ret = calloc(1, sizeof(struct xy));
   if (ret == NULL) abort();
 
   ret->common.clear = clear;
-  ret->common.append = (void (*)(view *, ...))append;
-  ret->common.set = set;
+
+  switch (mode) {
+  case XY_LOOP_MODE:
+    ret->common.append = (void (*)(view *, ...))append_loop;
+    ret->common.set = set;
+    ret->length = length;
+    ret->insert_point = 0;
+    break;
+  case XY_FORCED_MODE:
+    ret->common.append = (void (*)(view *, ...))append_forced;
+    ret->common.set = NULL;
+    ret->length = 0;
+    ret->max_length = length;
+    break;
+  }
 
   ret->refresh_rate = refresh_rate;
   ret->g = g;
   ret->w = w;
   ret->plot = xy_plot_new_plot(g, w, color);
 
-  ret->length = length;
   ret->x = calloc(length, sizeof(float)); if (ret->x == NULL) abort();
   ret->y = calloc(length, sizeof(float)); if (ret->y == NULL) abort();
-  ret->insert_point = 0;
 
   if (pthread_mutex_init(&ret->lock, NULL)) abort();
 
diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c
index 48ab4c5ca76503ee8fe62cb5203eeaa9a7424729..010dd36f3192334b1df919ed2b6219c506246166 100644
--- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c
+++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c
@@ -1842,6 +1842,7 @@ void rx_ulsch(PHY_VARS_eNB *phy_vars_eNB,
 
   T(T_ENB_PHY_PUSCH_IQ, T_INT(eNB_id), T_INT(UE_id), T_INT(phy_vars_eNB->proc[sched_subframe].frame_rx),
     T_INT(subframe), T_INT(ulsch[UE_id]->harq_processes[harq_pid]->nb_rb),
+    T_INT(frame_parms->N_RB_UL), T_INT(frame_parms->symbols_per_tti),
     T_BUFFER(eNB_pusch_vars->rxdataF_comp[eNB_id][0],
              2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ frame_parms->N_RB_UL *12*frame_parms->symbols_per_tti*2));
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index 837706de232975139113c507a3c374c227410121..1f488687a335e99172f44fc3b9f3d3d4ae7b42d9 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -130,6 +130,8 @@ void rx_sdu(
 
   T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP),
     T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu));
+  T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP),
+    T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), T_BUFFER(sduP, sdu_lenP));
 
   eNB->eNB_stats[CC_idP].ulsch_bytes_rx=sdu_lenP;
   eNB->eNB_stats[CC_idP].total_ulsch_bytes_rx+=sdu_lenP;
@@ -313,6 +315,8 @@ void rx_sdu(
 
     T(T_ENB_MAC_UE_UL_SDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP),
       T_INT(rx_lcids[i]), T_INT(rx_lengths[i]));
+    T(T_ENB_MAC_UE_UL_SDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP),
+      T_INT(rx_lcids[i]), T_INT(rx_lengths[i]), T_BUFFER(payload_ptr, rx_lengths[i]));
 
     switch (rx_lcids[i]) {
     case CCCH :
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR/dataTypes.h b/targets/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR/dataTypes.h
index cba2b7341e2ad89ccdb8047d5fbb9628674e629e..c97ac7857df021918df23abbddee645ed18e35e1 100644
--- a/targets/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR/dataTypes.h
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR/dataTypes.h
@@ -14,14 +14,15 @@ typedef struct
     int16_t q;
 } complex16_t;
 
-typedef struct
+class SamplesPacket
 {
+  public:
     uint64_t timestamp; //timestamp of the packet
     uint16_t first; //index of first unused sample in samples[]
     uint16_t last; //end index of samples
     static const uint16_t samplesCount = 1024; //maximum number of samples in packet
     complex16_t samples[samplesCount]; //must be power of two    
-} SamplesPacket;
+};
 
 complex16_t operator &=(complex16_t & other1, const complex16_t & other) // copy assignment
 {    
@@ -30,4 +31,4 @@ complex16_t operator &=(complex16_t & other1, const complex16_t & other) // copy
     return other1;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index ca97ad0e225acc5ca7f4205d30a3c7e7209dbf09..3f419ed49ca8cfe3dc98cbd9df33a69d38e08b55 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -490,6 +490,7 @@ void help (void) {
 #if T_TRACER
   printf("  --T_port [port]    use given port\n");
   printf("  --T_nowait         don't wait for tracer, start immediately\n");
+  printf("  --T_dont_fork      to ease debugging with gdb\n");
 #endif
   printf(RESET);
   fflush(stdout);
@@ -2332,6 +2333,7 @@ static void get_options (int argc, char **argv)
 #if T_TRACER
     LONG_OPTION_T_PORT,
     LONG_OPTION_T_NOWAIT,
+    LONG_OPTION_T_DONT_FORK,
 #endif
   };
 
@@ -2355,6 +2357,7 @@ static void get_options (int argc, char **argv)
 #if T_TRACER
     {"T_port",                 required_argument, 0, LONG_OPTION_T_PORT},
     {"T_nowait",               no_argument,       0, LONG_OPTION_T_NOWAIT},
+    {"T_dont_fork",            no_argument,       0, LONG_OPTION_T_DONT_FORK},
 #endif
 
     {NULL, 0, NULL, 0}
@@ -2457,6 +2460,12 @@ static void get_options (int argc, char **argv)
       T_wait = 0;
       break;
     }
+
+    case LONG_OPTION_T_DONT_FORK: {
+      extern int T_dont_fork;
+      T_dont_fork = 1;
+      break;
+    }
 #endif
 
     case 'A':
@@ -2822,6 +2831,7 @@ static void get_options (int argc, char **argv)
 #if T_TRACER
 int T_wait = 1;       /* by default we wait for the tracer */
 int T_port = 2021;    /* default port to listen to to wait for the tracer */
+int T_dont_fork = 0;  /* default is to fork, see 'T_init' to understand */
 #endif
 
 int main( int argc, char **argv )
@@ -2894,7 +2904,7 @@ int main( int argc, char **argv )
     openair0_cfg[0].configFilename = rf_config_file;
   
 #if T_TRACER
-  T_init(T_port, T_wait);
+  T_init(T_port, T_wait, T_dont_fork);
 #endif
 
   // initialize the log (see log.h for details)
diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c
index dfbf8f9676c6db683c6312ef150041ea288ea791..744952b5d0d23d4affe9cea28653a4d959404c7d 100644
--- a/targets/SIMU/USER/oaisim.c
+++ b/targets/SIMU/USER/oaisim.c
@@ -250,6 +250,7 @@ help (void)
 #if T_TRACER
   printf ("--T_port [port]    use given port\n");
   printf ("--T_nowait         don't wait for tracer, start immediately\n");
+  printf ("--T_dont_fork      to ease debugging with gdb\n");
 #endif
 }
 
@@ -1258,6 +1259,7 @@ l2l1_task (void *args_p)
 #if T_TRACER
 int T_wait = 1;       /* by default we wait for the tracer */
 int T_port = 2021;    /* default port to listen to to wait for the tracer */
+int T_dont_fork = 0;  /* default is to fork, see 'T_init' to understand */
 #endif
 
 /*------------------------------------------------------------------------------*/
@@ -1294,7 +1296,7 @@ main (int argc, char **argv)
   get_simulation_options (argc, argv); //Command-line options
 
 #if T_TRACER
-  T_init(T_port, T_wait);
+  T_init(T_port, T_wait, T_dont_fork);
 #endif
 
   // Initialize VCD LOG module
diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c
index f8043b2cfd710c11f5a41cea72ae73387ef37721..a5acb2616a81054ad9dbea9f9d39248fd5d11d03 100644
--- a/targets/SIMU/USER/oaisim_functions.c
+++ b/targets/SIMU/USER/oaisim_functions.c
@@ -216,6 +216,7 @@ void get_simulation_options(int argc, char *argv[])
 #if T_TRACER
     LONG_OPTION_T_PORT,
     LONG_OPTION_T_NOWAIT,
+    LONG_OPTION_T_DONT_FORK,
 #endif
   };
 
@@ -254,6 +255,7 @@ void get_simulation_options(int argc, char *argv[])
 #if T_TRACER
     {"T_port",                 required_argument, 0, LONG_OPTION_T_PORT},
     {"T_nowait",               no_argument,       0, LONG_OPTION_T_NOWAIT},
+    {"T_dont_fork",            no_argument,       0, LONG_OPTION_T_DONT_FORK},
 #endif
 
     {NULL, 0, NULL, 0}
@@ -436,6 +438,12 @@ void get_simulation_options(int argc, char *argv[])
       T_wait = 0;
       break;
     }
+
+    case LONG_OPTION_T_DONT_FORK: {
+      extern int T_dont_fork;
+      T_dont_fork = 1;
+      break;
+    }
 #endif
 
     case 'a':