From c866677a8f5fd5132006ffb1208141bcddcc0406 Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Wed, 23 Aug 2017 10:22:08 +0200
Subject: [PATCH] mobipass standalone driver

How to use:

1 - compilation of softmodem:
  ./build_oai --eNB -t ETHERNET

2 - compilation of mobipass driver:
  cd cmake_targets/lte_build_oai/build
  make oai_mobipass
  ln -sf liboai_mobipass.so liboai_transpro.so

3 - configuration:
  edit the configuration file, set "node_timing" to
  "synch_to_mobipass_standalone"
  that is, have the line:
    node_timing               = "synch_to_mobipass_standalone";

4 - run:
  run as usual: sudo ./lte-softmodem -C <configuration file>
---
 cmake_targets/CMakeLists.txt           |  13 +
 openair1/PHY/LTE_TRANSPORT/if5_tools.c | 400 +++++++++++++++----------
 openair1/PHY/defs.h                    |   5 +-
 openair2/ENB_APP/enb_config.c          |   2 +
 targets/ARCH/mobipass/interface.c      | 189 ++++++++++++
 targets/ARCH/mobipass/mobipass.c       | 200 +++++++++++++
 targets/ARCH/mobipass/mobipass.h       |  38 +++
 targets/ARCH/mobipass/queues.c         | 281 +++++++++++++++++
 targets/ARCH/mobipass/queues.h         |  15 +
 targets/RT/USER/lte-enb.c              |  45 +++
 10 files changed, 1034 insertions(+), 154 deletions(-)
 create mode 100644 targets/ARCH/mobipass/interface.c
 create mode 100644 targets/ARCH/mobipass/mobipass.c
 create mode 100644 targets/ARCH/mobipass/mobipass.h
 create mode 100644 targets/ARCH/mobipass/queues.c
 create mode 100644 targets/ARCH/mobipass/queues.h

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 83b9eb7c2f0..50415c18bc4 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -532,6 +532,19 @@ set(TPLIB_ETHERNET_SOURCE
   )
 add_library(oai_eth_transpro MODULE ${TPLIB_ETHERNET_SOURCE} )
 
+include_directories("${OPENAIR_TARGETS}/ARCH/mobipass/")
+set(TPLIB_MOBIPASS_SOURCE
+  ${OPENAIR_TARGETS}/ARCH/mobipass/interface.c
+  ${OPENAIR_TARGETS}/ARCH/mobipass/mobipass.c
+  ${OPENAIR_TARGETS}/ARCH/mobipass/queues.c
+  )
+add_library(oai_mobipass MODULE ${TPLIB_MOBIPASS_SOURCE} )
+
+# Hide all functions/variables in the mobipass library.
+# Use __attribute__((__visibility__("default")))
+# in the source code to unhide a function/variable.
+get_target_property(mobipas_cflags oai_mobipass COMPILE_FLAGS)
+set_target_properties(oai_mobipass PROPERTIES COMPILE_FLAGS "${mobipass_cflags} -fvisibility=hidden")
 
 ##########################################################
 
diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
index b4fc0722d17..117cd8707d9 100644
--- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
@@ -181,63 +181,114 @@ void send_IF5(PHY_VARS_eNB *eNB, openair0_timestamp proc_timestamp, int subframe
       }    
     }
   } else if (packet_type == IF5_MOBIPASS) {    
-    uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-    
-    __m128i *data_block=NULL, *data_block_head=NULL;
+    /* the only difference between mobipass standalone and the other one
+     * is the timestamp in trx_write_func, but let's duplicate anyway
+     * (plus we don't call malloc for the standalone case)
+     */
+    if (eNB->node_timing == synch_to_mobipass_standalone) {
+      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
 
-    __m128i *txp128;
-    __m128i t0, t1;
+      __m128i *data_block=NULL, *data_block_head=NULL;
+      __m128i *txp128;
+      __m128i t0, t1;
 
-    // tx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-    tx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-    IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES);
-    data_block_head = (__m128i *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
-  
-    header->flags = 0;
-    header->fifo_status = 0;  
-    header->seqno = *seqno;
-    header->ack = 0;
-    header->word0 = 0;  
-    
-    txp[0] = (void*)&eNB->common_vars.txdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
-    txp128 = (__m128i *) txp[0];
-              
-    for (packet_id=0; packet_id<fp->samples_per_tti/db_fulllength; packet_id++) {
-      header->time_stamp = htonl((uint32_t)(proc_timestamp + packet_id*db_fulllength));
-      data_block = data_block_head; 
-    
-      for (i=0; i<db_fulllength>>2; i+=2) {
-        t0 = _mm_srai_epi16(*txp128++, 4);
-        t1 = _mm_srai_epi16(*txp128++, 4);   
-//        *data_block++ = _mm_packs_epi16(t0, t1);     
-       _mm_storeu_si128(data_block++, _mm_packs_epi16(t0, t1));     
+      unsigned char _tx_buffer[MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)];
+      tx_buffer=(int32_t *)_tx_buffer;
+
+      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES);
+      data_block_head = (__m128i *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
+
+      header->flags = 0;
+      header->fifo_status = 0;
+      header->seqno = *seqno;
+      header->ack = 0;
+      header->word0 = 0;
+
+      txp[0] = (void*)&eNB->common_vars.txdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
+      txp128 = (__m128i *) txp[0];
+
+      for (packet_id=0; packet_id<fp->samples_per_tti/db_fulllength; packet_id++) {
+        header->time_stamp = htonl((uint32_t)(proc_timestamp + packet_id*db_fulllength));
+        data_block = data_block_head;
+
+        for (i=0; i<db_fulllength>>2; i+=2) {
+          t0 = _mm_srai_epi16(*txp128++, 4);
+          t1 = _mm_srai_epi16(*txp128++, 4);
+         _mm_storeu_si128(data_block++, _mm_packs_epi16(t0, t1));
+        }
+
+        // Write the packet to the fronthaul
+        if ((eNB->ifdevice.trx_write_func(&eNB->ifdevice,
+                                          proc_timestamp + packet_id*db_fulllength,
+                                          (void**)&tx_buffer,
+                                          db_fulllength,
+                                          1,
+                                          IF5_MOBIPASS)) < 0) {
+          perror("ETHERNET write for IF5_MOBIPASS\n");
+        }
+        header->seqno += 1;
       }
+      *seqno = header->seqno;
+      tx_buffer = NULL;
+    } else {
+      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
       
-      // Write the packet to the fronthaul
-      if ((eNB->ifdevice.trx_write_func(&eNB->ifdevice,
-                                        packet_id,
-                                        (void**)&tx_buffer,
-                                        db_fulllength,
-                                        1,
-                                        IF5_MOBIPASS)) < 0) {
-        perror("ETHERNET write for IF5_MOBIPASS\n");
-      }
+      __m128i *data_block=NULL, *data_block_head=NULL;
+
+      __m128i *txp128;
+      __m128i t0, t1;
+
+      // tx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
+      tx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
+      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES);
+      data_block_head = (__m128i *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
+    
+      header->flags = 0;
+      header->fifo_status = 0;  
+      header->seqno = *seqno;
+      header->ack = 0;
+      header->word0 = 0;  
+      
+      txp[0] = (void*)&eNB->common_vars.txdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
+      txp128 = (__m128i *) txp[0];
+                
+      for (packet_id=0; packet_id<fp->samples_per_tti/db_fulllength; packet_id++) {
+        header->time_stamp = htonl((uint32_t)(proc_timestamp + packet_id*db_fulllength));
+        data_block = data_block_head; 
+      
+        for (i=0; i<db_fulllength>>2; i+=2) {
+          t0 = _mm_srai_epi16(*txp128++, 4);
+          t1 = _mm_srai_epi16(*txp128++, 4);   
+//        *data_block++ = _mm_packs_epi16(t0, t1);     
+         _mm_storeu_si128(data_block++, _mm_packs_epi16(t0, t1));     
+        }
+        
+        // Write the packet to the fronthaul
+        if ((eNB->ifdevice.trx_write_func(&eNB->ifdevice,
+                                          packet_id,
+                                          (void**)&tx_buffer,
+                                          db_fulllength,
+                                          1,
+                                          IF5_MOBIPASS)) < 0) {
+          perror("ETHERNET write for IF5_MOBIPASS\n");
+        }
 #ifdef DEBUG_DL_MOBIPASS
-     if ((subframe==0)&&(dummy_cnt == 100)) {
-        memcpy((void*)&dummy_buffer[packet_id*db_fulllength*2],(void*)data_block_head,db_fulllength*2);
-      }
+       if ((subframe==0)&&(dummy_cnt == 100)) {
+          memcpy((void*)&dummy_buffer[packet_id*db_fulllength*2],(void*)data_block_head,db_fulllength*2);
+        }
 #endif
-      header->seqno += 1;    
-    }  
-    *seqno = header->seqno;
+        header->seqno += 1;    
+      }  
+      *seqno = header->seqno;
 
 #ifdef DEBUG_DL_MOBIPASS
-    uint8_t txe;
-    txe = dB_fixed(signal_energy(txp[0],fp->samples_per_tti));
-    if (txe > 0){
-      LOG_D(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, txe);
-    }
+      uint8_t txe;
+      txe = dB_fixed(signal_energy(txp[0],fp->samples_per_tti));
+      if (txe > 0){
+        LOG_D(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, txe);
+      }
 #endif  
+    }
   } else {    
     AssertFatal(1==0, "send_IF5 - Unknown packet_type %x", packet_type);     
   }  
@@ -391,131 +442,176 @@ void recv_IF5(PHY_VARS_eNB *eNB, openair0_timestamp *proc_timestamp, int subfram
     *proc_timestamp = timestamp[0];
       
   } else if (packet_type == IF5_MOBIPASS) {
-    
-    uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-    openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
+    if (eNB->node_timing == synch_to_mobipass_standalone) {
+      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
+      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
+      int subframe_skip = 0;
+      int reset_flag = 0;
+      int32_t *rx_buffer=NULL;
+      __m128i *data_block=NULL, *data_block_head=NULL;
+      __m128i *rxp128;
+      __m128i r0;
+
+      unsigned char _rx_buffer[MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)];
+      rx_buffer = (int32_t *)_rx_buffer;
+      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES);
+      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
+
+      rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
+      rxp128 = (__m128i *) (rxp[0]);
+
+      eNB_proc_t *proc = &eNB->proc;
+
+      packet_id=0;
+      while(packet_id<fp->samples_per_tti/db_fulllength) {
+        data_block = data_block_head;
+
+        eNB->ifdevice.trx_read_func(&eNB->ifdevice,
+                                         &timestamp_mobipass[packet_id],
+                                         (void**)&rx_buffer,
+                                         db_fulllength,
+                                          1
+                                          );
+
+          //store rxdata and increase packet_id
+          rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
+          rxp128 = (__m128i *) (rxp[0]);
+          for (i=0; i<db_fulllength>>2; i+=2) {
+            r0 = _mm_loadu_si128(data_block++);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
+          }
+          packet_id++;
+      }//end while
+
+      *proc_timestamp = ntohl(timestamp_mobipass[0]);
+    } else {
+      
+      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
+      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
 #ifdef DEBUG_UL_MOBIPASS
-    int lower_offset = 0;
-    int  upper_offset = 70000;
+      int lower_offset = 0;
+      int  upper_offset = 70000;
 #endif
-    int subframe_skip = 0;
-    int reset_flag = 0;
-    int32_t *rx_buffer=NULL;
-    __m128i *data_block=NULL, *data_block_head=NULL;
-    __m128i *rxp128;
-    __m128i r0;
-
-    //rx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-    rx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-    IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES);
-    data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
- 
-    rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
-    rxp128 = (__m128i *) (rxp[0]);
- 
-    eNB_proc_t *proc = &eNB->proc;
+      int subframe_skip = 0;
+      int reset_flag = 0;
+      int32_t *rx_buffer=NULL;
+      __m128i *data_block=NULL, *data_block_head=NULL;
+      __m128i *rxp128;
+      __m128i r0;
+
+      //rx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
+      rx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
+      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES);
+      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
+   
+      rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms.samples_per_tti];
+      rxp128 = (__m128i *) (rxp[0]);
+   
+      eNB_proc_t *proc = &eNB->proc;
 /*
- //   while(packet_id<fp->samples_per_tti/db_fulllength) {
-      data_block = data_block_head;
-
-      eNB->ifdevice.trx_read_func(&eNB->ifdevice,
-                                       &ts0,
-                                       (void**)&rx_buffer,
-                                       db_fulllength,
-                                        1
-                                        );
-
-      if ((header->seqno == 1)&&(first_packet==1))  { 
-         first_packet = 0;  //ignore the packets before synchnorization
-         packet_id = 0;
-        ts_offset = ntohl(ts0);
-      } 
-      if (first_packet==0) { 
-        packet_cnt++;
-        ts = ntohl(ts0);
-        packet_id = (ts-ts_offset)/db_fulllength;
-        packet_id = packet_id % (fp->samples_per_tti/db_fulllength);
-
-        printf("[IF5_tools]packet_id:%d\n", packet_id);
-        // if (ts_stored == 0) {
-        //   ts_stored = 1;
-        *proc_timestamp = ntohl(ts - (packet_id*db_fulllength));
-        // }
-        rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
-        rxp128 = (__m128i *) (rxp[0]);
+   //   while(packet_id<fp->samples_per_tti/db_fulllength) {
+        data_block = data_block_head;
 
-        for (i=0; i<db_fulllength>>2; i+=2) {
-          r0 = _mm_loadu_si128(data_block++);
-          *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-          *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
+        eNB->ifdevice.trx_read_func(&eNB->ifdevice,
+                                         &ts0,
+                                         (void**)&rx_buffer,
+                                         db_fulllength,
+                                          1
+                                          );
+
+        if ((header->seqno == 1)&&(first_packet==1))  { 
+           first_packet = 0;  //ignore the packets before synchnorization
+           packet_id = 0;
+          ts_offset = ntohl(ts0);
+        } 
+        if (first_packet==0) { 
+          packet_cnt++;
+          ts = ntohl(ts0);
+          packet_id = (ts-ts_offset)/db_fulllength;
+          packet_id = packet_id % (fp->samples_per_tti/db_fulllength);
+
+          printf("[IF5_tools]packet_id:%d\n", packet_id);
+          // if (ts_stored == 0) {
+          //   ts_stored = 1;
+          *proc_timestamp = ntohl(ts - (packet_id*db_fulllength));
+          // }
+          rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
+          rxp128 = (__m128i *) (rxp[0]);
+
+          for (i=0; i<db_fulllength>>2; i+=2) {
+            r0 = _mm_loadu_si128(data_block++);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
+          }
         }
-      }
-  //  }//end while
+    //  }//end while
 */
- 
+   
 
-    packet_id=0; 
-    while(packet_id<fp->samples_per_tti/db_fulllength) {
-      data_block = data_block_head;
+      packet_id=0; 
+      while(packet_id<fp->samples_per_tti/db_fulllength) {
+        data_block = data_block_head;
 
-      eNB->ifdevice.trx_read_func(&eNB->ifdevice,
-                                       &timestamp_mobipass[packet_id],
-                                       (void**)&rx_buffer,
-                                       db_fulllength,
-                                        1
-                                        );
+        eNB->ifdevice.trx_read_func(&eNB->ifdevice,
+                                         &timestamp_mobipass[packet_id],
+                                         (void**)&rx_buffer,
+                                         db_fulllength,
+                                          1
+                                          );
 #ifdef DEBUG_UL_MOBIPASS
-      if (((proc->timestamp_tx + lower_offset) > ntohl(timestamp_mobipass[packet_id])) || ((proc->timestamp_tx + upper_offset) < ntohl(timestamp_mobipass[packet_id]))) {
-        //ignore the packet
-        subframe_skip_extra = (subframe_skip_extra + 1)%67;         
-       LOG_D("[Mobipass] ignored packet, id:[%d,%d], proc->timestamp_tx:%llu, proc->timestamp_rx:%llu, seqno:%d\n", packet_id,subframe_skip_extra, proc->timestamp_tx, ntohl(timestamp_mobipass[packet_id]), header->seqno);
-      }             
+        if (((proc->timestamp_tx + lower_offset) > ntohl(timestamp_mobipass[packet_id])) || ((proc->timestamp_tx + upper_offset) < ntohl(timestamp_mobipass[packet_id]))) {
+          //ignore the packet
+          subframe_skip_extra = (subframe_skip_extra + 1)%67;         
+         LOG_D("[Mobipass] ignored packet, id:[%d,%d], proc->timestamp_tx:%llu, proc->timestamp_rx:%llu, seqno:%d\n", packet_id,subframe_skip_extra, proc->timestamp_tx, ntohl(timestamp_mobipass[packet_id]), header->seqno);
+        }             
 #endif
-      //skip SUBFRAME_SKIP_NUM_MOBIPASS additional UL packets
-      if ((start_flag == 1) && (subframe_skip < SUBFRAME_SKIP_NUM_MOBIPASS)){
-        subframe_skip++;
-        offset_cnt = header->seqno;
-      } else {
-        if ((offset_cnt != header->seqno) && (start_flag == 0) && (proc->first_rx > 3)){
+        //skip SUBFRAME_SKIP_NUM_MOBIPASS additional UL packets
+        if ((start_flag == 1) && (subframe_skip < SUBFRAME_SKIP_NUM_MOBIPASS)){
+          subframe_skip++;
+          offset_cnt = header->seqno;
+        } else {
+          if ((offset_cnt != header->seqno) && (start_flag == 0) && (proc->first_rx > 3)){
 #ifdef DEBUG_UL_MOBIPASS
-           LOG_D(PHY,"[Mobipass] Reset sequence number, offset_cnt:%d, header->seqno:%d, packet_id:%d\n", offset_cnt, header->seqno, packet_id);
+             LOG_D(PHY,"[Mobipass] Reset sequence number, offset_cnt:%d, header->seqno:%d, packet_id:%d\n", offset_cnt, header->seqno, packet_id);
 #endif
-           reset_flag=1;
-        }
-        if ((reset_flag == 1) && (proc->first_rx > 3 ) && (start_flag == 0) && (packet_id == 0)) {
-           packet_id = 1;  
-           reset_flag = 0;
+             reset_flag=1;
+          }
+          if ((reset_flag == 1) && (proc->first_rx > 3 ) && (start_flag == 0) && (packet_id == 0)) {
+             packet_id = 1;  
+             reset_flag = 0;
+          }
+          start_flag = 0;
+
+          //store rxdata and increase packet_id
+          rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
+          rxp128 = (__m128i *) (rxp[0]);
+          for (i=0; i<db_fulllength>>2; i+=2) {
+            r0 = _mm_loadu_si128(data_block++);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
+            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
+          }   
+          packet_id++; 
+          offset_cnt = (header->seqno+1)&255;
         }
-        start_flag = 0;
-
-        //store rxdata and increase packet_id
-        rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
-        rxp128 = (__m128i *) (rxp[0]);
-        for (i=0; i<db_fulllength>>2; i+=2) {
-          r0 = _mm_loadu_si128(data_block++);
-          *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-          *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-        }   
-        packet_id++; 
-        offset_cnt = (header->seqno+1)&255;
-      }
-    }//end while
-  
-      *proc_timestamp = ntohl(timestamp_mobipass[0]); 
+      }//end while
+    
+        *proc_timestamp = ntohl(timestamp_mobipass[0]); 
 #ifdef DEBUG_UL_MOBIPASS
-   LOG_I(PHY,"[Mobipass][Recv_MOBIPASS] timestamp: %llu\n ",  *proc_timestamp);
+     LOG_I(PHY,"[Mobipass][Recv_MOBIPASS] timestamp: %llu\n ",  *proc_timestamp);
 if (eNB->CC_id>0) {
-    rxe = dB_fixed(signal_energy(rxp[0],fp->samples_per_tti)); 
-    if (rxe > 0){
-      LOG_I(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (*proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, rxe);
+      rxe = dB_fixed(signal_energy(rxp[0],fp->samples_per_tti)); 
+      if (rxe > 0){
+        LOG_I(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (*proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, rxe);
 //    write_output("rxsigmb.m","rxs",(void*)dummy_buffer_rx, fp->samples_per_tti,1, 5); 
 //    exit(-1);
-    }
+      }
 }
 #endif
 
 
-   
+     
+    }
   } else {
     AssertFatal(1==0, "recv_IF5 - Unknown packet_type %x", packet_type);     
   }  
diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index ad1d788a570..d386a2ce988 100644
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -165,8 +165,9 @@ typedef enum  {
 } eNB_func_t;
 
 typedef enum {
-  synch_to_ext_device=0,  // synch to RF or Ethernet device
-  synch_to_other          // synch to another source (timer, other CC_id)
+  synch_to_ext_device=0,        // synch to RF or Ethernet device
+  synch_to_other,               // synch to another source (timer, other CC_id)
+  synch_to_mobipass_standalone  // special case for mobipass in standalone mode
 } eNB_timing_t;
 #endif
 
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 153c89b3e2b..8001f909e79 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -947,6 +947,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
                 enb_properties.properties[enb_properties_index]->cc_node_timing[j] = synch_to_ext_device;
               } else if (strcmp(cc_node_timing, "synch_to_other") == 0) {
                 enb_properties.properties[enb_properties_index]->cc_node_timing[j] = synch_to_other;
+              } else if (strcmp(cc_node_timing, "synch_to_mobipass_standalone") == 0) {
+                enb_properties.properties[enb_properties_index]->cc_node_timing[j] = synch_to_mobipass_standalone;
               } else {
                 AssertError (0, parse_errors ++,
                              "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for node_function choice: SYNCH_TO_DEVICE or SYNCH_TO_OTHER !\n",
diff --git a/targets/ARCH/mobipass/interface.c b/targets/ARCH/mobipass/interface.c
new file mode 100644
index 00000000000..d9cc0edeb08
--- /dev/null
+++ b/targets/ARCH/mobipass/interface.c
@@ -0,0 +1,189 @@
+#include <arpa/inet.h>
+#include <linux/if_packet.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/sysctl.h>
+#include <sys/sysctl.h>
+
+#include "common_lib.h"
+#include "ethernet_lib.h"
+
+#include "mobipass.h"
+#include "queues.h"
+
+struct mobipass_header {
+  uint16_t flags;
+  uint16_t fifo_status;
+  unsigned char seqno;
+  unsigned char ack;
+  uint32_t word0;
+  uint32_t timestamp;
+} __attribute__((__packed__));
+
+int mobipass_start(openair0_device *device) { init_mobipass(device->priv); return 0; }
+int mobipass_request(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
+int mobipass_reply(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
+int mobipass_get_stats(openair0_device* device) { return 0; }
+int mobipass_reset_stats(openair0_device* device) { return 0; }
+void mobipass_end(openair0_device *device) {}
+int mobipass_stop(openair0_device *device) { return 0; }
+int mobipass_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) { return 0; }
+int mobipass_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) { return 0; }
+
+int mobipass_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
+  mobipass_state_t *mobi = device->priv;
+  struct mobipass_header *mh = (struct mobipass_header *)(((char *)buff[0]) + 14);
+  mobi->mobipass_write_last_timestamp += 640;
+  mobi->mobipass_write_last_timestamp %= mobi->samples_per_1024_frames;
+  mh->timestamp = htonl(ntohl(mh->timestamp) % mobi->samples_per_1024_frames);
+  if (mobi->mobipass_write_last_timestamp != ntohl(mh->timestamp))
+    { printf("mobipass: ERROR: bad timestamp wanted %d got %d\n", mobi->mobipass_write_last_timestamp, ntohl(mh->timestamp)); exit(1); }
+//printf("__write nsamps %d timestamps %ld seqno %d (packet timestamp %d)\n", nsamps, timestamp, mh->seqno, ntohl(mh->timestamp));
+  if (nsamps != 640) abort();
+  enqueue_to_mobipass(mobi->qstate, buff[0]);
+  return nsamps;
+}
+
+int mobipass_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+  mobipass_state_t *mobi = device->priv;
+//printf("__read nsamps %d return timestamp %d\n", nsamps, ts);
+  *timestamp = htonl(mobi->mobipass_read_ts);
+  mobi->mobipass_read_ts += nsamps;
+  mobi->mobipass_read_ts %= mobi->samples_per_1024_frames;
+  if (nsamps != 640) { printf("mobipass: ERROR: bad nsamps %d, should be 640\n", nsamps); fflush(stdout); abort(); }
+
+  dequeue_from_mobipass(mobi->qstate, ntohl(*timestamp), buff[0]);
+
+#if 1
+  struct mobipass_header *mh = (struct mobipass_header *)(((char *)buff[0]) + 14);
+  mh->flags = 0;
+  mh->fifo_status = 0;
+  mh->seqno = mobi->mobipass_read_seqno++;
+  mh->ack = 0;
+  mh->word0 = 0;
+  mh->timestamp = htonl(mobi->mobipass_read_ts);
+#endif
+
+  return nsamps;
+}
+
+/* this is the only function in the library that is visible from outside
+ * because in CMakeLists.txt we use -fvisibility=hidden
+ */
+__attribute__((__visibility__("default")))
+int transport_init(openair0_device *device, openair0_config_t *openair0_cfg,
+        eth_params_t * eth_params )
+{
+  //init_mobipass();
+
+  mobipass_state_t *mobi = (mobipass_state_t*)malloc(sizeof(mobipass_state_t));
+  memset(mobi, 0, sizeof(mobipass_state_t));
+
+  if (eth_params->transp_preference != 4) goto err;
+  if (eth_params->if_compress != 0) goto err;
+
+  /* only 50 PRBs handled for the moment */
+  if (openair0_cfg[0].sample_rate != 15360000) {
+    printf("mobipass: ERROR: only 50 PRBs supported\n");
+    exit(1);
+  }
+
+  mobi->eth.flags = ETH_RAW_IF5_MOBIPASS;
+  mobi->eth.compression = NO_COMPRESS;
+  device->Mod_id           = 0;//num_devices_eth++;
+  device->transp_type      = ETHERNET_TP;
+
+  device->trx_start_func   = mobipass_start;
+  device->trx_request_func = mobipass_request;
+  device->trx_reply_func   = mobipass_reply;
+  device->trx_get_stats_func   = mobipass_get_stats;
+  device->trx_reset_stats_func = mobipass_reset_stats;
+  device->trx_end_func         = mobipass_end;
+  device->trx_stop_func        = mobipass_stop;
+  device->trx_set_freq_func = mobipass_set_freq;
+  device->trx_set_gains_func = mobipass_set_gains;
+  device->trx_write_func   = mobipass_write;
+  device->trx_read_func    = mobipass_read;
+
+  device->priv = mobi;
+
+  mobi->eth.if_name = strdup(eth_params->local_if_name);
+  if (mobi->eth.if_name == NULL) abort();
+
+  if (sscanf(eth_params->my_addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+          &mobi->eth_local[0],
+          &mobi->eth_local[1],
+          &mobi->eth_local[2],
+          &mobi->eth_local[3],
+          &mobi->eth_local[4],
+          &mobi->eth_local[5]) != 6) {
+    printf("mobipass: ERROR: bad local ethernet address '%s', check configuration file\n",
+           eth_params->my_addr);
+    exit(1);
+  }
+
+  if (sscanf(eth_params->remote_addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+          &mobi->eth_remote[0],
+          &mobi->eth_remote[1],
+          &mobi->eth_remote[2],
+          &mobi->eth_remote[3],
+          &mobi->eth_remote[4],
+          &mobi->eth_remote[5]) != 6) {
+    printf("mobipass: ERROR: bad remote ethernet address '%s', check configuration file\n",
+           eth_params->remote_addr);
+    exit(1);
+  }
+
+  /* note: this only works for 50 PRBs */
+  mobi->samples_per_1024_frames = 7680*2*10*1024;
+
+  /* TX starts at subframe 4, let's pretend we are at the right position */
+  /* note: this only works for 50 PRBs */
+  mobi->mobipass_write_last_timestamp = 4*7680*2-640;
+
+  /* device specific */
+  openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
+  openair0_cfg[0].iq_txshift = eth_params->iq_txshift;// shift
+  openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance;
+
+  /* this is useless, I think */
+  if (device->host_type == BBU_HOST) {
+    /*Note scheduling advance values valid only for case 7680000 */    
+    switch ((int)openair0_cfg[0].sample_rate) {
+    case 30720000:
+      openair0_cfg[0].samples_per_packet    = 3840;     
+      break;
+    case 23040000:     
+      openair0_cfg[0].samples_per_packet    = 2880;
+      break;
+    case 15360000:
+      openair0_cfg[0].samples_per_packet    = 1920;      
+      break;
+    case 7680000:
+      openair0_cfg[0].samples_per_packet    = 960;     
+      break;
+    case 1920000:
+      openair0_cfg[0].samples_per_packet    = 240;     
+      break;
+    default:
+      printf("mobipass: ERROR: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
+      exit(-1);
+      break;
+    }
+  }
+
+  device->openair0_cfg=&openair0_cfg[0];
+
+  return 0;
+
+err:
+  printf("mobipass: ERROR: bad configuration file?\n");
+  exit(1);
+}
diff --git a/targets/ARCH/mobipass/mobipass.c b/targets/ARCH/mobipass/mobipass.c
new file mode 100644
index 00000000000..2a2a86ba749
--- /dev/null
+++ b/targets/ARCH/mobipass/mobipass.c
@@ -0,0 +1,200 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <linux/if_packet.h>
+#include <netinet/ether.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "queues.h"
+#include "mobipass.h"
+
+/******************************************************************/
+/* time begin                                                     */
+/******************************************************************/
+
+#include <time.h>
+
+static void init_time(mobipass_state_t *mobi)
+{
+  struct timespec now;
+  if (clock_gettime(CLOCK_MONOTONIC_RAW, &now)) abort();
+  mobi->t0 = (uint64_t)now.tv_sec * (uint64_t)1000000000 + (uint64_t)now.tv_nsec;
+}
+
+/* called before sending data to mobipass
+ * waits if called too early with respect to system clock
+ * does not wait more than 1ms in any case
+ */
+static void synch_time(mobipass_state_t *mobi, uint32_t ts)
+{
+  if (ts < mobi->synch_time_last_ts) mobi->synch_time_mega_ts++;
+  mobi->synch_time_last_ts = ts;
+
+  struct timespec now;
+  if (clock_gettime(CLOCK_MONOTONIC_RAW, &now)) abort();
+
+  uint64_t tnow;
+  tnow = (uint64_t)now.tv_sec * (uint64_t)1000000000 + (uint64_t)now.tv_nsec;
+
+  uint64_t cur = tnow - mobi->t0;
+
+  /* 15360000 samples/second, in nanoseconds:
+   *  = 15360000 / 1000000000 = 1536 / 100000 = 48 / 3125*/
+
+  uint64_t ts_ns = ((uint64_t)ts + mobi->synch_time_mega_ts * (uint64_t)mobi->samples_per_1024_frames) * (uint64_t)3125 / (uint64_t)48;
+
+  /* TODO: if cur is way higher than ts_ns, we are very late, log something? */
+  if (cur >= ts_ns) return;
+
+  uint64_t delta = ts_ns - cur;
+  /* don't sleep more than 1 ms */
+  if (delta > 1000*1000) delta = 1000*1000;
+  delta = delta/1000;
+  if (delta) usleep(delta);
+}
+
+/******************************************************************/
+/* time end                                                       */
+/******************************************************************/
+
+struct ethernet_header {
+  unsigned char dst[6];
+  unsigned char src[6];
+  uint16_t packet_type;
+} __attribute__((__packed__));
+
+struct mobipass_header {
+  uint16_t flags;
+  uint16_t fifo_status;
+  unsigned char seqno;
+  unsigned char ack;
+  uint32_t word0;
+  uint32_t timestamp;
+} __attribute__((__packed__));
+
+static void do_receive(mobipass_state_t *mobi, unsigned char *b)
+{
+  if (recv(mobi->sock, b, 14+14+1280, 0) != 14+14+1280) { perror("recv"); exit(1); }
+  struct mobipass_header *mh = (struct mobipass_header *)(b+14);
+  mh->timestamp = htonl((ntohl(mh->timestamp)-45378/*40120*/) % mobi->samples_per_1024_frames);
+//printf("recv timestamp %u\n", ntohl(mh->timestamp));
+}
+
+/* receiver thread */
+static void *receiver(void *_mobi)
+{
+  mobipass_state_t *mobi = _mobi;
+  unsigned char receive_packet[14 + 14 + 1280];
+  while (1) {
+    do_receive(mobi, receive_packet);
+    enqueue_from_mobipass(mobi->qstate, receive_packet);
+  }
+  return 0;
+}
+
+static void do_send(mobipass_state_t *mobi, int seqno, uint32_t ts,
+    unsigned char *packet)
+{
+  struct ethernet_header *eh = (struct ethernet_header *)packet;
+  struct mobipass_header *mh = (struct mobipass_header *)(packet+14);
+
+  ts %= mobi->samples_per_1024_frames;
+//printf("SEND seqno %d ts %d\n", seqno, ts);
+
+  memcpy(eh->dst, mobi->eth_remote, 6);
+  memcpy(eh->src, mobi->eth_local, 6);
+
+  eh->packet_type = htons(0xbffe);
+
+  mh->flags = 0;
+  mh->fifo_status = 0;
+  mh->seqno = seqno;
+  mh->ack = 0;
+  mh->word0 = 0;
+  mh->timestamp = htonl(ts);
+
+  synch_time(mobi, ts);
+
+  if (send(mobi->sock, packet, 14+14+1280, 0) != 14+14+1280) { perror("send"); exit(1); }
+}
+
+/* sender thread */
+static void *sender(void *_mobi)
+{
+  mobipass_state_t *mobi = _mobi;
+  unsigned char packet[14 + 14 + 1280];
+  uint32_t ts = 0;
+  unsigned char seqno = 0;
+  while (1) {
+    dequeue_to_mobipass(mobi->qstate, ts, packet);
+    do_send(mobi, seqno, ts, packet);
+    seqno++;
+    ts += 640;
+    ts %= mobi->samples_per_1024_frames;
+  }
+  return 0;
+}
+
+static void new_thread(void *(*f)(void *), void *data)
+{
+  pthread_t t;
+  pthread_attr_t att;
+
+  if (pthread_attr_init(&att))
+    { fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
+  if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
+    { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
+  if (pthread_attr_setstacksize(&att, 10000000))
+    { fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); }
+  if (pthread_create(&t, &att, f, data))
+    { fprintf(stderr, "pthread_create err\n"); exit(1); }
+  if (pthread_attr_destroy(&att))
+    { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
+}
+
+void init_mobipass(mobipass_state_t *mobi)
+{
+  int i;
+  unsigned char data[14+14+640];
+  memset(data, 0, 14+14+640);
+
+  init_time(mobi);
+
+  mobi->qstate = init_queues(mobi->samples_per_1024_frames);
+
+  for (i = 0; i < 24*4; i++) {
+    uint32_t timestamp = i*640;
+    unsigned char seqno = i;
+    struct mobipass_header *mh = (struct mobipass_header *)(data+14);
+    mh->seqno = seqno;
+    mh->timestamp = htonl(timestamp);
+    enqueue_to_mobipass(mobi->qstate, data);
+  }
+
+  mobi->sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
+  if (mobi->sock == -1) { perror("socket"); exit(1); }
+
+  /* get if index */
+  struct ifreq if_index;
+  memset(&if_index, 0, sizeof(struct ifreq));
+  strcpy(if_index.ifr_name, mobi->eth.if_name);
+  if (ioctl(mobi->sock, SIOCGIFINDEX, &if_index)<0) {perror("SIOCGIFINDEX");exit(1);}
+
+  struct sockaddr_ll local_addr;
+  local_addr.sll_family   = AF_PACKET;
+  local_addr.sll_ifindex  = if_index.ifr_ifindex;
+  local_addr.sll_protocol = htons(0xbffe);
+  local_addr.sll_halen    = ETH_ALEN;
+  local_addr.sll_pkttype  = PACKET_OTHERHOST;
+
+  if (bind(mobi->sock, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_ll))<0)
+    { perror("bind"); exit(1); }
+
+  new_thread(receiver, mobi);
+  new_thread(sender, mobi);
+}
diff --git a/targets/ARCH/mobipass/mobipass.h b/targets/ARCH/mobipass/mobipass.h
new file mode 100644
index 00000000000..885ee5d4502
--- /dev/null
+++ b/targets/ARCH/mobipass/mobipass.h
@@ -0,0 +1,38 @@
+#ifndef _MOBIPASS_H_
+#define _MOBIPASS_H_
+
+#include <stdint.h>
+#include "ethernet_lib.h"
+
+typedef struct {
+  /* this has to come first */
+  eth_state_t eth;
+
+  void *qstate;
+
+  uint8_t eth_local[6];
+  uint8_t eth_remote[6];
+
+  int samples_per_1024_frames;
+
+  /* variables used by the function interface.c:mobipass_read */
+  uint32_t mobipass_read_ts;
+  unsigned char mobipass_read_seqno;
+
+  /* variables used by the function interface.c:mobipass_write */
+  uint32_t mobipass_write_last_timestamp;
+
+  /* variables used by the function mobipass.c:[init_time|synch_time] */
+  uint64_t t0;
+
+  /* variables used by the function mobipass.c:synch_time */
+  uint32_t synch_time_last_ts;
+  uint64_t synch_time_mega_ts;
+
+  /* sock is used in mobipass.c */
+  int sock;
+} mobipass_state_t;
+
+void init_mobipass(mobipass_state_t *mobi);
+
+#endif /* _MOBIPASS_H_ */
diff --git a/targets/ARCH/mobipass/queues.c b/targets/ARCH/mobipass/queues.c
new file mode 100644
index 00000000000..23fe1a2cf6b
--- /dev/null
+++ b/targets/ARCH/mobipass/queues.c
@@ -0,0 +1,281 @@
+#include "queues.h"
+#include "mobipass.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#define QSIZE 10000
+
+struct mobipass_header {
+  uint16_t flags;
+  uint16_t fifo_status;
+  unsigned char seqno;
+  unsigned char ack;
+  uint32_t word0;
+  uint32_t timestamp;
+} __attribute__((__packed__));
+
+struct queue {
+  unsigned char buf[QSIZE][14+14+640*2];
+  volatile int start;
+  volatile int len;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+};
+
+typedef struct {
+  struct queue to_mobipass;
+  struct queue from_mobipass;
+  int samples_per_1024_frames;
+
+  /* variables used by dequeue_from_mobipass */
+  int dequeue_from_mobipass_seqno;
+
+  /* variables used to manage logging of "missing samples"
+   * coming from mobipass. (Yes, this can happen, mostly
+   * at startup.)
+   * This idea is to print some logs, but not too much to
+   * flood stdout. (This is already a bad idea to call
+   * printf in a 'realtime' thread.)
+   */
+  int no_sample_log_running;
+  uint32_t no_sample_log_start_sample;
+  uint32_t no_sample_log_next_sample;
+} queue_state_t;
+
+static void enqueue(void *data, struct queue *q)
+{
+  int pos;
+
+  if (pthread_mutex_lock(&q->mutex)) abort();
+  if (q->len == QSIZE) {
+    printf("mobipass: WARNING: enqueue: full\n");
+    goto done;
+  }
+
+  pos = (q->start + q->len) % QSIZE;
+  memcpy(q->buf[pos], data, 14+14+640*2);
+  q->len++;
+
+done:
+  if (pthread_cond_signal(&q->cond)) abort();
+  if (pthread_mutex_unlock(&q->mutex)) abort();
+}
+
+void enqueue_to_mobipass(void *_qstate, void *data)
+{
+  queue_state_t *qstate = _qstate;
+  enqueue(data, &qstate->to_mobipass);
+}
+
+void dequeue_to_mobipass(void *_qstate, uint32_t timestamp, void *data)
+{
+  queue_state_t *qstate = _qstate;
+  if (pthread_mutex_lock(&qstate->to_mobipass.mutex)) abort();
+  while (qstate->to_mobipass.len == 0) {
+    if (pthread_cond_wait(&qstate->to_mobipass.cond, &qstate->to_mobipass.mutex)) abort();
+  }
+
+  memcpy(data, qstate->to_mobipass.buf[qstate->to_mobipass.start], 14+14+640*2);
+  qstate->to_mobipass.len--;
+  qstate->to_mobipass.start = (qstate->to_mobipass.start + 1) % QSIZE;
+
+  if (pthread_mutex_unlock(&qstate->to_mobipass.mutex)) abort();
+}
+
+void enqueue_from_mobipass(void *_qstate, void *data)
+{
+  queue_state_t *qstate = _qstate;
+  struct mobipass_header *mh = (struct mobipass_header *)((char*)data+14);
+  mh->timestamp = htonl(ntohl(mh->timestamp) % qstate->samples_per_1024_frames);
+//printf("from mobipass! timestamp %u seqno %d\n", ntohl(mh->timestamp), mh->seqno);
+  enqueue(data, &qstate->from_mobipass);
+}
+
+static int cmp_timestamps(uint32_t a, uint32_t b, int samples_per_1024_frames)
+{
+  if (a == b) return 0;
+  if (a < b) {
+    if (b-a > samples_per_1024_frames/2) return 1;
+    return -1;
+  }
+  if (a-b > samples_per_1024_frames/2) return -1;
+  return 1;
+}
+
+/*************************************************/
+/* missing samples logging management begin      */
+/*************************************************/
+
+static void log_flush(queue_state_t *qstate)
+{
+  /* print now if there is something to print */
+  if (qstate->no_sample_log_running == 0)
+    return;
+  qstate->no_sample_log_running = 0;
+  printf("mobipass: WARNING: missing samples [%u-%u]\n",
+      qstate->no_sample_log_start_sample,
+      (uint32_t)(qstate->no_sample_log_next_sample-1));
+}
+
+static void log_missed_sample(queue_state_t *qstate, uint32_t timestamp)
+{
+  /* collect data, print if there is a discontinuity */
+  if (qstate->no_sample_log_running == 0 ||
+      timestamp != qstate->no_sample_log_next_sample) {
+    log_flush(qstate);
+    qstate->no_sample_log_start_sample = timestamp;
+  }
+
+  qstate->no_sample_log_next_sample = timestamp+1;
+  qstate->no_sample_log_running = 1;
+}
+
+static void log_flush_if_old(queue_state_t *qstate, uint32_t timestamp)
+{
+  /* log every second (more or less), if we have to */
+  /* note that if mobipass stopped, it may take much more
+   * than one second to log, due to the sleeps done while
+   * waiting for samples (that never come)
+   */
+  if (qstate->no_sample_log_running == 1 &&
+      labs(timestamp-qstate->no_sample_log_start_sample) > qstate->samples_per_1024_frames/10)
+    log_flush(qstate);
+}
+
+/*************************************************/
+/* missing samples logging management end        */
+/*************************************************/
+
+/* to be called with lock on */
+static void get_sample_from_mobipass(queue_state_t *qstate, char *I, char *Q, uint32_t timestamp)
+{
+  unsigned char *b = NULL;
+  unsigned char *data = NULL;
+  struct mobipass_header *mh = NULL;
+  uint32_t packet_timestamp = 0;
+
+#if 0
+uint32_t old_start = qstate->from_mobipass.start;
+uint32_t old_len = qstate->from_mobipass.len;
+b = qstate->from_mobipass.buf[qstate->from_mobipass.start];
+mh = (struct mobipass_header *)(b+14);
+uint32_t old_pts = qstate->from_mobipass.len ? ntohl(mh->timestamp) : -1;
+b=NULL;
+mh=NULL;
+#endif
+
+  while (qstate->from_mobipass.len) {
+    b = qstate->from_mobipass.buf[qstate->from_mobipass.start];
+    mh = (struct mobipass_header *)(b+14);
+    data = b + 14*2;
+    packet_timestamp = ntohl(mh->timestamp);
+    if (cmp_timestamps(timestamp, packet_timestamp, qstate->samples_per_1024_frames) < 0) goto nodata;
+    if (cmp_timestamps(timestamp, (packet_timestamp+640) % qstate->samples_per_1024_frames, qstate->samples_per_1024_frames) < 0) break;
+    qstate->from_mobipass.len--;
+    qstate->from_mobipass.start = (qstate->from_mobipass.start+1) % QSIZE;
+  }
+
+  if (qstate->from_mobipass.len == 0) goto nodata;
+
+  if (timestamp == (packet_timestamp + 639) % qstate->samples_per_1024_frames) {
+    qstate->from_mobipass.len--;
+    qstate->from_mobipass.start = (qstate->from_mobipass.start+1) % QSIZE;
+  }
+
+  if (timestamp < packet_timestamp) timestamp += qstate->samples_per_1024_frames;
+
+  *I = data[(timestamp - packet_timestamp) * 2];
+  *Q = data[(timestamp - packet_timestamp) * 2 + 1];
+
+  return;
+
+nodata:
+  *I = 0;
+  *Q = 0;
+
+  log_missed_sample(qstate, timestamp);
+
+#if 0
+printf("no sample timestamp %u pt %u start %d old_start %d old_pt %u len %d old len %d\n", timestamp, packet_timestamp, qstate->from_mobipass.start, old_start, old_pts, qstate->from_mobipass.len, old_len);
+#endif
+}
+
+/* doesn't work with delay more than 1s */
+static void wait_for_data(pthread_cond_t *cond, pthread_mutex_t *mutex, int delay_us)
+{
+  struct timeval now;
+  struct timespec target;
+  gettimeofday(&now, NULL);
+  target.tv_sec = now.tv_sec;
+  target.tv_nsec = (now.tv_usec + delay_us) * 1000;
+  if (target.tv_nsec >= 1000 * 1000 * 1000) { target.tv_nsec -= 1000 * 1000 * 1000; target.tv_sec++; }
+  int err = pthread_cond_timedwait(cond, mutex, &target);
+  if (err != 0 && err != ETIMEDOUT) { printf("mobipass: ERROR: pthread_cond_timedwait: err (%d) %s\n", err, strerror(err)); abort(); }
+}
+
+/* don't block infinitely when waiting for data
+ * if waiting for too long, just return some zeros
+ */
+void dequeue_from_mobipass(void *_qstate, uint32_t timestamp, void *data)
+{
+  queue_state_t *qstate = _qstate;
+  int i;
+//  int ts = timestamp;
+  int waiting_allowed;
+
+  if (pthread_mutex_lock(&qstate->from_mobipass.mutex)) abort();
+
+  if (qstate->from_mobipass.len == 0) {
+//printf("sleep 1\n");
+    wait_for_data(&qstate->from_mobipass.cond, &qstate->from_mobipass.mutex, 2000); //1000/3);
+  }
+
+  waiting_allowed = qstate->from_mobipass.len != 0;
+
+  for (i = 0; i < 640*2; i+=2) {
+    if (qstate->from_mobipass.len == 0 && waiting_allowed) {
+//printf("sleep 2\n");
+      wait_for_data(&qstate->from_mobipass.cond, &qstate->from_mobipass.mutex, 2000); //1000/3);
+      waiting_allowed = qstate->from_mobipass.len != 0;
+    }
+
+    get_sample_from_mobipass(qstate, (char*)data + 14*2 + i, (char*)data + 14*2 + i+1, timestamp % qstate->samples_per_1024_frames);
+    timestamp++;
+  }
+
+  log_flush_if_old(qstate, timestamp);
+
+  if (pthread_mutex_unlock(&qstate->from_mobipass.mutex)) abort();
+
+  struct mobipass_header *mh = (struct mobipass_header *)(((char *)data) + 14);
+  mh->flags = 0;
+  mh->fifo_status = 0;
+  mh->seqno = qstate->dequeue_from_mobipass_seqno++;
+  mh->ack = 0;
+  mh->word0 = 0;
+  mh->timestamp = htonl(timestamp);
+}
+
+void *init_queues(int samples_per_1024_frames)
+{
+  queue_state_t *q;
+  q = malloc(sizeof(queue_state_t));
+  if (q == NULL) abort();
+  memset(q, 0, sizeof(queue_state_t));
+
+  if (pthread_mutex_init(&q->to_mobipass.mutex, NULL)) abort();
+  if (pthread_mutex_init(&q->from_mobipass.mutex, NULL)) abort();
+  if (pthread_cond_init(&q->to_mobipass.cond, NULL)) abort();
+  if (pthread_cond_init(&q->from_mobipass.cond, NULL)) abort();
+
+  q->samples_per_1024_frames = samples_per_1024_frames;
+
+  return q;
+}
diff --git a/targets/ARCH/mobipass/queues.h b/targets/ARCH/mobipass/queues.h
new file mode 100644
index 00000000000..eee3642a5b2
--- /dev/null
+++ b/targets/ARCH/mobipass/queues.h
@@ -0,0 +1,15 @@
+#ifndef _QUEUES_H_
+#define _QUEUES_H_
+
+#include <stdint.h>
+
+void enqueue_to_mobipass(void *qstate, void *data);
+void dequeue_to_mobipass(void *qstate, uint32_t timestamp, void *data);
+
+void enqueue_from_mobipass(void *qstate, void *receive_packet);
+void dequeue_from_mobipass(void *qstate, uint32_t timestamp, void *data);
+
+/* returns a queue state type, as opaque data structure */
+void *init_queues(int samples_per_1024_frames);
+
+#endif /* _QUEUES_H_ */
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 5cbe0fe1d4d..171a54ac63f 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -433,6 +433,14 @@ void tx_fh_if5_mobipass(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
     send_IF5(eNB, proc->timestamp_tx, proc->subframe_tx, &seqno, IF5_MOBIPASS); 
 }
 
+void tx_fh_if5_mobipass_standalone(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, proc->timestamp_tx&0xffffffff );
+  if ((eNB->frame_parms.frame_type==FDD) ||
+      ((eNB->frame_parms.frame_type==TDD) &&
+       (subframe_select(&eNB->frame_parms,proc->subframe_tx) != SF_UL)))
+    send_IF5(eNB, proc->timestamp_tx, proc->subframe_tx, &seqno, IF5_MOBIPASS);
+}
+
 void tx_fh_if4p5(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
   if ((eNB->frame_parms.frame_type==FDD) ||
       ((eNB->frame_parms.frame_type==TDD) &&
@@ -1097,6 +1105,38 @@ void rx_fh_if5(PHY_VARS_eNB *eNB,int *frame, int *subframe) {
 
 }
 
+void rx_fh_if5_mobipass_standalone(PHY_VARS_eNB *eNB,int *frame, int *subframe)
+{
+  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
+  eNB_proc_t *proc = &eNB->proc;
+
+  recv_IF5(eNB, &proc->timestamp_rx, *subframe, IF5_MOBIPASS);
+//printf("in rx_fh_if5_mobipass timestamp from recv_IF5 %ld\n", proc->timestamp_rx);
+
+  proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
+  proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
+//  T(T_SUBFRAME, T_INT(proc->frame_rx), T_INT(proc->subframe_rx), T_STRING(__FUNCTION__));
+
+  if (proc->first_rx == 0) {
+    if (proc->subframe_rx != *subframe){
+      LOG_E(PHY,"rx_fh_if5: Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe);
+      exit_fun("Exiting");
+    }
+
+    if (proc->frame_rx != *frame) {
+      LOG_E(PHY,"rx_fh_if5: Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
+      exit_fun("Exiting");
+    }
+  } else {
+    proc->first_rx--;
+    *frame = proc->frame_rx;
+    *subframe = proc->subframe_rx;
+  }
+
+  proc->timestamp_tx = proc->timestamp_rx +  (4*fp->samples_per_tti);
+
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
+}
 
 void rx_fh_if4p5(PHY_VARS_eNB *eNB,int *frame,int *subframe) {
 
@@ -2132,6 +2172,11 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst
            eNB->fh_asynch         = fh_if5_asynch_UL;
 
         }
+        else if (eNB->node_timing == synch_to_mobipass_standalone) {
+           eNB->tx_fh             = tx_fh_if5_mobipass_standalone;
+           eNB->rx_fh             = rx_fh_if5_mobipass_standalone;
+           eNB->fh_asynch         = NULL;
+        }
         else {
            eNB->tx_fh             = tx_fh_if5;
            eNB->rx_fh             = rx_fh_if5;
-- 
GitLab