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, + ×tamp_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, - ×tamp_mobipass[packet_id], - (void**)&rx_buffer, - db_fulllength, - 1 - ); + eNB->ifdevice.trx_read_func(&eNB->ifdevice, + ×tamp_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