git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7885 818b1a75-f10b-46b9-bf7c-635c3b92a50f
556 lines
18 KiB
C
556 lines
18 KiB
C
/*******************************************************************************
|
|
OpenAirInterface
|
|
Copyright(c) 1999 - 2014 Eurecom
|
|
|
|
OpenAirInterface is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
|
|
OpenAirInterface is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenAirInterface.The full GNU General Public License is
|
|
included in this distribution in the file called "COPYING". If not,
|
|
see <http://www.gnu.org/licenses/>.
|
|
|
|
Contact Information
|
|
OpenAirInterface Admin: openair_admin@eurecom.fr
|
|
OpenAirInterface Tech : openair_tech@eurecom.fr
|
|
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
|
|
|
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
|
|
|
*******************************************************************************/
|
|
/*! \file UE_transport_IQ.c
|
|
* \brief UE transport IQ sampels
|
|
* \author Katerina Trilyraki, Navid Nikaein, Raymond Knopp
|
|
* \date 2015
|
|
* \version 0.1
|
|
* \company Eurecom
|
|
* \maintainer: navid.nikaein@eurecom.fr
|
|
* \note
|
|
* \warning very experimental
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
|
|
#include "common_lib.h"
|
|
#include "PHY/defs.h"
|
|
#include "rrh_gw.h"
|
|
#include "rrh_gw_externs.h"
|
|
|
|
#define START_CMD 1
|
|
#define RRH_UE_PORT 51000
|
|
#define RRH_UE_DEST_IP "127.0.0.1"
|
|
#define PRINTF_PERIOD 3750
|
|
|
|
/******************************************************************************
|
|
** FUNCTION PROTOTYPES **
|
|
******************************************************************************/
|
|
void *rrh_proc_UE_thread(void *);
|
|
void *rrh_UE_thread(void *);
|
|
void *rrh_UE_rx_thread(void *);
|
|
void *rrh_UE_tx_thread(void *);
|
|
|
|
|
|
|
|
openair0_timestamp timestamp_UE_tx[4]= {0,0,0,0},timestamp_UE_rx[4]= {0,0,0,0};
|
|
openair0_timestamp nrt_UE_counter[4]= {0,0,0,0};
|
|
|
|
pthread_t main_rrh_UE_thread,main_rrh_proc_UE_thread;
|
|
pthread_attr_t attr, attr_proc;
|
|
struct sched_param sched_param_rrh, sched_param_rrh_proc;
|
|
pthread_cond_t sync_UE_cond[4];
|
|
pthread_mutex_t sync_UE_mutex[4];
|
|
|
|
int32_t overflow_rx_buffer_UE[4]= {0,0,0,0};
|
|
int32_t nsamps_UE[4]= {0,0,0,0};
|
|
int32_t UE_tx_started=0,UE_rx_started=0;
|
|
int32_t RT_flag_UE=0, NRT_flag_UE=1;
|
|
int32_t counter_UE_rx[4]= {0,0,0,0};
|
|
int32_t counter_UE_tx[4]= {0,0,0,0};
|
|
int32_t **tx_buffer_UE, **rx_buffer_UE;
|
|
|
|
int sync_UE_rx[4]= {-1,-1,-1,-1};
|
|
void *rrh_UE_thread_status;
|
|
|
|
|
|
void *rx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx
|
|
void *tx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx
|
|
|
|
|
|
void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) {
|
|
|
|
int i;
|
|
int error_code_UE, error_code_proc_UE;
|
|
void *tmp;
|
|
|
|
RT_flag_UE=RT_flag;
|
|
NRT_flag_UE=NRT_flag;
|
|
|
|
pthread_attr_init(&attr);
|
|
sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
pthread_attr_init(&attr_proc);
|
|
sched_param_rrh_proc.sched_priority = sched_get_priority_max(SCHED_FIFO-1);
|
|
|
|
pthread_attr_setschedparam(&attr,&sched_param_rrh);
|
|
pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
|
|
pthread_attr_setschedparam(&attr_proc,&sched_param_rrh_proc);
|
|
pthread_attr_setschedpolicy(&attr_proc,SCHED_FIFO-1);
|
|
|
|
|
|
for (i=0; i<4; i++) {
|
|
pthread_mutex_init(&sync_UE_mutex[i],NULL);
|
|
pthread_cond_init(&sync_UE_cond[i],NULL);
|
|
}
|
|
|
|
error_code_UE = pthread_create(&main_rrh_UE_thread, &attr, rrh_UE_thread, (void *)dev_ue);
|
|
error_code_proc_UE = pthread_create(&main_rrh_proc_UE_thread, &attr_proc, rrh_proc_UE_thread, (void *)dev_ue);
|
|
|
|
if (error_code_UE) {
|
|
printf("Error while creating UE thread\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if (error_code_proc_UE) {
|
|
printf("Error while creating UE proc thread\n");
|
|
exit(-1);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*! \fn void *rrh_proc_UE_thread((void *)dev_ue)
|
|
* \brief this function
|
|
* \param[in]
|
|
* \param[out]
|
|
* \return
|
|
* \note
|
|
* @ingroup _oai
|
|
*/
|
|
void *rrh_proc_UE_thread(void * arg) {
|
|
|
|
int antenna_index,i;
|
|
openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0;
|
|
struct timespec time_req, time_rem;
|
|
int16_t *txp,*rxp;
|
|
unsigned int samples_per_frame=0;
|
|
rrh_module_t *dev=(rrh_module_t *)arg;
|
|
|
|
samples_per_frame= dev->eth_dev.openair0_cfg.samples_per_frame;
|
|
AssertFatal(samples_per_frame <=0, "invalide samples_per_frame !%u\n",samples_per_frame);
|
|
|
|
time_req.tv_sec = 0;
|
|
time_req.tv_nsec = 1000;
|
|
|
|
while (rrh_exit==0) {
|
|
//wait until some data has been copied
|
|
for (antenna_index=0; antenna_index<4; antenna_index++) {
|
|
if (sync_UE_rx[antenna_index]==0) {
|
|
if (!UE_tx_started) {
|
|
UE_tx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data
|
|
if (RT_flag_UE==1) {
|
|
last_hw_counter=hw_counter;
|
|
}
|
|
} else {
|
|
if (RT_flag_UE==1) {
|
|
if (hw_counter > last_hw_counter+1) {
|
|
printf("L1");
|
|
// goto end_copy_UE;
|
|
} else {
|
|
while (hw_counter < last_hw_counter+1)
|
|
nanosleep(&time_req,&time_rem);
|
|
}
|
|
}
|
|
}
|
|
|
|
truncated_timestamp = timestamp_UE_tx[antenna_index]%(samples_per_frame);
|
|
truncated_timestamp_final = (timestamp_UE_tx[antenna_index]+nsamps_UE[antenna_index])%samples_per_frame;
|
|
|
|
if ((truncated_timestamp + nsamps_UE[antenna_index]) > samples_per_frame) {
|
|
if ((timestamp_eNB_rx[antenna_index]%samples_per_frame < nsamps_UE[antenna_index]) && (eNB_rx_started==1)) {
|
|
overflow_rx_buffer_eNB[antenna_index]++;
|
|
printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp);
|
|
|
|
if (NRT_flag_UE==1) {
|
|
while ((timestamp_eNB_rx[antenna_index]%samples_per_frame) < nsamps_UE[antenna_index])
|
|
nanosleep(&time_req,&time_rem);
|
|
}
|
|
}
|
|
|
|
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp];
|
|
txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp];
|
|
|
|
for (i=0; i<(samples_per_frame<<1)-(truncated_timestamp<<1); i++) {
|
|
rxp[i] = txp[i]>>6;
|
|
}
|
|
|
|
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][0];
|
|
txp = (int16_t*)&tx_buffer_UE[antenna_index][0];
|
|
|
|
for (i=0; i<nsamps_eNB[antenna_index]-(samples_per_frame)+(truncated_timestamp); i++) {
|
|
rxp[i] = txp[i]>>6;
|
|
}
|
|
|
|
} else {
|
|
if (((truncated_timestamp < (timestamp_eNB_rx[antenna_index]%samples_per_frame)) &&
|
|
(truncated_timestamp_final > (timestamp_eNB_rx[antenna_index]%samples_per_frame))) &&
|
|
(eNB_rx_started==1)) {
|
|
overflow_rx_buffer_eNB[antenna_index]++;
|
|
printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp);
|
|
|
|
if (NRT_flag_UE==1) {
|
|
while (truncated_timestamp_final > timestamp_eNB_rx[antenna_index]%samples_per_frame)
|
|
nanosleep(&time_req,&time_rem);
|
|
}
|
|
}
|
|
|
|
rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp];
|
|
txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp];
|
|
|
|
for (i=0; i<(nsamps_eNB[antenna_index]); i++) {
|
|
rxp[i] =txp[i]>>6;
|
|
}
|
|
|
|
}
|
|
//end_copy_UE :
|
|
last_hw_counter=hw_counter;
|
|
pthread_mutex_lock(&sync_UE_mutex[antenna_index]);
|
|
sync_UE_rx[antenna_index]--;
|
|
pthread_mutex_unlock(&sync_UE_mutex[antenna_index]);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*! \fn void *rrh_UE_thread(void *arg)
|
|
* \brief this function
|
|
* \param[in]
|
|
* \param[out]
|
|
* \return
|
|
* \note
|
|
* @ingroup _oai
|
|
*/
|
|
void *rrh_UE_thread(void *arg) {
|
|
|
|
rrh_module_t *dev=(rrh_module_t *)arg;
|
|
|
|
struct sched_param sched_param_UE_rx, sched_param_UE_tx;
|
|
int16_t i,cmd; //,nsamps,antenna_index;
|
|
ssize_t bytes_received;
|
|
struct timespec time_req_1us, time_rem_1us;
|
|
pthread_t UE_rx_thread, UE_tx_thread;
|
|
pthread_attr_t attr_UE_rx, attr_UE_tx;
|
|
int error_code_UE_rx, error_code_UE_tx;
|
|
void *tmp;
|
|
unsigned int samples_per_frame=0;
|
|
|
|
samples_per_frame= dev->eth_dev.openair0_cfg.samples_per_frame;
|
|
time_req_1us.tv_sec = 0;
|
|
time_req_1us.tv_nsec = 1000;
|
|
|
|
while (rrh_exit==0) {
|
|
|
|
cmd=dev->eth_dev.trx_start_func(&dev->eth_dev);
|
|
|
|
/* allocate memory for TX/RX buffers */
|
|
rx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.rx_num_channels*sizeof(int32_t*));
|
|
tx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg.tx_num_channels*sizeof(int32_t*));
|
|
|
|
for (i=0; i<dev->eth_dev.openair0_cfg.rx_num_channels; i++) {
|
|
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4));
|
|
memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4));
|
|
rx_buffer_UE[i]=(tmp+4*sizeof(int32_t));
|
|
}
|
|
|
|
for (i=0; i<dev->eth_dev.openair0_cfg.tx_num_channels; i++) {
|
|
tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4));
|
|
memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4));
|
|
tx_buffer_UE[i]=(tmp+4*sizeof(int32_t));
|
|
}
|
|
|
|
printf("Client %s:%d is connected (DL_RB=%d) rt=%d|%d. \n" , dev->eth_dev.openair0_cfg.remote_ip,
|
|
dev->eth_dev.openair0_cfg.remote_port,
|
|
dev->eth_dev.openair0_cfg.num_rb_dl,
|
|
dev->eth_dev.openair0_cfg.rx_num_channels,
|
|
dev->eth_dev.openair0_cfg.tx_num_channels);
|
|
|
|
if (cmd==START_CMD) {
|
|
|
|
pthread_attr_init(&attr_UE_rx);
|
|
pthread_attr_init(&attr_UE_tx);
|
|
sched_param_UE_rx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
sched_param_UE_tx.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
pthread_attr_setschedparam(&attr_UE_rx,&sched_param_UE_rx);
|
|
pthread_attr_setschedparam(&attr_UE_tx,&sched_param_UE_tx);
|
|
pthread_attr_setschedpolicy(&attr_UE_rx,SCHED_FIFO);
|
|
pthread_attr_setschedpolicy(&attr_UE_tx,SCHED_FIFO);
|
|
|
|
error_code_UE_rx = pthread_create(&UE_rx_thread, &attr_UE_rx, rrh_UE_rx_thread, (void *)&dev);
|
|
error_code_UE_tx = pthread_create(&UE_tx_thread, &attr_UE_tx, rrh_UE_tx_thread, (void *)&dev);
|
|
|
|
if (error_code_UE_rx) {
|
|
printf("Error while creating UE RX thread\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if (error_code_UE_tx) {
|
|
printf("Error while creating UE TX thread\n");
|
|
exit(-1);
|
|
}
|
|
|
|
while (rrh_exit==0)
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
|
|
rrh_UE_thread_status = 0;
|
|
pthread_exit(&rrh_UE_thread_status);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*! \fn void *rrh_UE_rx_thread(void *arg)
|
|
* \brief this function
|
|
* \param[in]
|
|
* \param[out]
|
|
* \return
|
|
* \note
|
|
* @ingroup _oai
|
|
*/
|
|
void *rrh_UE_rx_thread(void *arg) {
|
|
|
|
rrh_module_t *dev = (rrh_module_t *)arg;
|
|
struct timespec time0,time1,time2;
|
|
struct timespec time_req_1us, time_rem_1us;
|
|
ssize_t bytes_sent;
|
|
int antenna_index, nsamps;
|
|
int trace_cnt=0;
|
|
unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0;
|
|
unsigned int samples_per_frame=0;
|
|
openair0_timestamp temp, last_hw_counter=0;
|
|
|
|
antenna_index = 0;
|
|
nsamps = dev->eth_dev.openair0_cfg.samples_per_packet;
|
|
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
|
|
|
while (rrh_exit == 0) {
|
|
if (!UE_rx_started) {
|
|
UE_rx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data
|
|
|
|
if (RT_flag_UE==1) {
|
|
last_hw_counter=hw_counter;
|
|
}
|
|
} else {
|
|
if (RT_flag_UE==1) {
|
|
if (hw_counter > last_hw_counter+1) {
|
|
printf("L1");
|
|
//goto end_copy_UE;
|
|
} else {
|
|
while (hw_counter < last_hw_counter+1)
|
|
nanosleep(&time_req_1us,&time_rem_1us);
|
|
}
|
|
}
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&time1);
|
|
|
|
// send return
|
|
|
|
if ((timestamp_UE_rx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit
|
|
if (((timestamp_eNB_tx[antenna_index]%(samples_per_frame)) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame))) && (eNB_tx_started==1)) {
|
|
printf("UE underflow wraparound timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",
|
|
(int)(timestamp_UE_rx[antenna_index]%(samples_per_frame)),
|
|
(int)(timestamp_eNB_tx[antenna_index]%samples_per_frame));
|
|
|
|
if (NRT_flag_UE==1) {
|
|
while ((timestamp_eNB_tx[antenna_index]%samples_per_frame) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame)))
|
|
nanosleep(&time_req_1us,&time_rem_1us);
|
|
}
|
|
}
|
|
|
|
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)];
|
|
if ((bytes_sent =dev->eth_dev.trx_write_func (dev,
|
|
timestamp_UE_rx[antenna_index],
|
|
rx_ue,
|
|
( samples_per_frame- (timestamp_eNB_rx[antenna_index]%(samples_per_frame)) ),
|
|
antenna_index,
|
|
0))<0)
|
|
perror("RRH UE : sendto for RX");
|
|
|
|
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][3];
|
|
if ((bytes_sent =dev->eth_dev.trx_write_func (dev,
|
|
timestamp_UE_rx[antenna_index],
|
|
rx_ue,
|
|
(nsamps - samples_per_frame + (timestamp_eNB_rx[antenna_index]%(samples_per_frame))),
|
|
antenna_index,
|
|
0))<0)
|
|
perror("RRH UE : sendto for RX");
|
|
|
|
} else {
|
|
if (((timestamp_UE_rx[antenna_index]%samples_per_frame)< timestamp_eNB_tx[antenna_index]%samples_per_frame) &&
|
|
(((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) &&
|
|
(eNB_tx_started==1) ) {
|
|
printf("UE underflow timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",
|
|
(int)(timestamp_UE_rx[antenna_index]%samples_per_frame),
|
|
(int)(timestamp_eNB_tx[antenna_index]%samples_per_frame));
|
|
|
|
if (NRT_flag_UE==1) {
|
|
while (((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) {
|
|
nanosleep(&time_req_1us,&time_rem_1us);
|
|
}
|
|
}
|
|
}
|
|
|
|
rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)];
|
|
if ((bytes_sent = dev->eth_dev.trx_write_func (dev,
|
|
timestamp_UE_rx[antenna_index],
|
|
rx_ue,
|
|
nsamps,
|
|
antenna_index,
|
|
0))<0)
|
|
perror("RRH UE thread: sendto for RX");
|
|
}
|
|
|
|
timestamp_UE_rx[antenna_index]+=nsamps;
|
|
last_hw_counter=hw_counter;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&time2);
|
|
|
|
if (trace_cnt++ > 10) {
|
|
total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec);
|
|
|
|
if (total_rx_time < 0) total_rx_time=1000000000-total_rx_time;
|
|
|
|
if ((total_rx_time > 0) && (total_rx_time < 1000000000)) {
|
|
trial++;
|
|
|
|
if (total_rx_time < min_rx_time)
|
|
min_rx_time = total_rx_time;
|
|
|
|
if (total_rx_time > max_rx_time)
|
|
max_rx_time = total_rx_time;
|
|
|
|
average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1);
|
|
}
|
|
|
|
if (s_period++ == PRINTF_PERIOD) {
|
|
s_period=0;
|
|
printf("Average UE RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time);
|
|
|
|
}
|
|
|
|
//printf("RX: t1 %llu (time from last send), t2 %llu (sendto of %lu bytes) total time : %llu\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), (long long unsigned int)(time2.tv_nsec - time1.tv_nsec),
|
|
// (nsamps<<2)+sizeof(openair0_timestamp),(long long unsigned int)(time2.tv_nsec - time0.tv_nsec));
|
|
|
|
}
|
|
|
|
memcpy(&time0,&time2,sizeof(struct timespec));
|
|
|
|
} //while (UE_exit==0)
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
/*! \fn void *rrh_UE_tx_thread(void *arg)
|
|
* \brief this function
|
|
* \param[in]
|
|
* \param[out]
|
|
* \return
|
|
* \note
|
|
* @ingroup _oai
|
|
*/
|
|
void *rrh_UE_tx_thread(void *arg) {
|
|
|
|
struct timespec time0a,time0,time1,time2;
|
|
struct timespec time_req_1us, time_rem_1us;
|
|
|
|
|
|
rrh_module_t *dev = (rrh_module_t *)arg;
|
|
ssize_t bytes_received;
|
|
int antenna_index, nsamps;
|
|
int trace_cnt=0;
|
|
unsigned int samples_per_frame=0;
|
|
|
|
antenna_index = 0;
|
|
nsamps = dev->eth_dev.openair0_cfg.samples_per_packet;
|
|
samples_per_frame = dev->eth_dev.openair0_cfg.samples_per_frame;
|
|
|
|
|
|
while (rrh_exit == 0) {
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&time0a);
|
|
|
|
bytes_received = dev->eth_dev.trx_read_func(dev,
|
|
×tamp_UE_tx[antenna_index],
|
|
tx_ue,
|
|
nsamps,
|
|
antenna_index);
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&time1);
|
|
|
|
if (NRT_flag_UE==1) {
|
|
nrt_UE_counter[antenna_index]++;
|
|
}
|
|
printf(" first part size: %d second part size: %d idx=%d \n",
|
|
(int32_t)(((samples_per_frame)<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)),
|
|
(nsamps<<2)-((samples_per_frame)<<2)+((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2),
|
|
timestamp_UE_tx[antenna_index]%(samples_per_frame));
|
|
if ((timestamp_UE_tx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit
|
|
memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)],(void*)(tx_ue[antenna_index]),
|
|
(samples_per_frame<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2));
|
|
|
|
memcpy(&tx_buffer_UE[antenna_index][0], (void*)(tx_ue[antenna_index]+(samples_per_frame*4)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)),
|
|
(nsamps<<2)-((samples_per_frame-(timestamp_UE_tx[antenna_index]%(samples_per_frame)))<<2));
|
|
//printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2));
|
|
} else {
|
|
memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)], (void*)(tx_ue[antenna_index]),(nsamps<<2));
|
|
}
|
|
|
|
while (sync_UE_rx[antenna_index]==0)
|
|
nanosleep(&time_req_1us,&time_rem_1us);
|
|
|
|
pthread_mutex_lock(&sync_UE_mutex[antenna_index]);
|
|
sync_UE_rx[antenna_index]++;
|
|
|
|
if (!sync_UE_rx[antenna_index]) {
|
|
counter_UE_tx[antenna_index]=(counter_UE_tx[antenna_index]+nsamps)%samples_per_frame;
|
|
nsamps_UE[antenna_index]=nsamps;
|
|
} else {
|
|
printf("rrh_eNB_proc thread is busy, will exit\n");
|
|
exit(-1);
|
|
}
|
|
|
|
pthread_mutex_unlock(&sync_UE_mutex[antenna_index]);
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&time2);
|
|
|
|
memcpy(&time0,&time2,sizeof(struct timespec));
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|