diff --git a/common/utils/system.c b/common/utils/system.c index dcec681e2dcf2596b78352560672439e7bba58ee..31c1035129998da9a8340b1b80895e0dd4d44120 100644 --- a/common/utils/system.c +++ b/common/utils/system.c @@ -28,13 +28,23 @@ * separate process solves this problem. */ +#define _GNU_SOURCE #include "system.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> - +#include <stdint.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include <common/utils/assertions.h> +#include <common/utils/LOG/log.h> #define MAX_COMMAND 4096 static int command_pipe_read; @@ -50,37 +60,37 @@ static int module_initialized = 0; /* util functions */ /********************************************************************/ -static void lock_system(void) -{ +static void lock_system(void) { if (pthread_mutex_lock(&lock) != 0) { printf("pthread_mutex_lock fails\n"); abort(); } } -static void unlock_system(void) -{ +static void unlock_system(void) { if (pthread_mutex_unlock(&lock) != 0) { printf("pthread_mutex_unlock fails\n"); abort(); } } -static void write_pipe(int p, char *b, int size) -{ +static void write_pipe(int p, char *b, int size) { while (size) { int ret = write(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } } -static void read_pipe(int p, char *b, int size) -{ +static void read_pipe(int p, char *b, int size) { while (size) { int ret = read(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } @@ -95,14 +105,13 @@ static void read_pipe(int p, char *b, int size) * when the main process exits, because then a "read" on the pipe * will return 0, in which case "read_pipe" exits. */ -static void background_system_process(void) -{ +static void background_system_process(void) { int len; int ret; char command[MAX_COMMAND+1]; while (1) { - read_pipe(command_pipe_read, (char*)&len, sizeof(int)); + read_pipe(command_pipe_read, (char *)&len, sizeof(int)); read_pipe(command_pipe_read, command, len); ret = system(command); write_pipe(result_pipe_write, (char *)&ret, sizeof(int)); @@ -114,8 +123,7 @@ static void background_system_process(void) /* return -1 on error, 0 on success */ /********************************************************************/ -int background_system(char *command) -{ +int background_system(char *command) { int res; int len; @@ -125,18 +133,22 @@ int background_system(char *command) } len = strlen(command)+1; + if (len > MAX_COMMAND) { printf("FATAL: command too long. Increase MAX_COMMAND (%d).\n", MAX_COMMAND); printf("command was: '%s'\n", command); abort(); } + /* only one command can run at a time, so let's lock/unlock */ lock_system(); - write_pipe(command_pipe_write, (char*)&len, sizeof(int)); + write_pipe(command_pipe_write, (char *)&len, sizeof(int)); write_pipe(command_pipe_write, command, len); - read_pipe(result_pipe_read, (char*)&res, sizeof(int)); + read_pipe(result_pipe_read, (char *)&res, sizeof(int)); unlock_system(); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) return -1; + return 0; } @@ -146,17 +158,16 @@ int background_system(char *command) /* to be called very early by the main processing */ /********************************************************************/ -void start_background_system(void) -{ +void start_background_system(void) { int p[2]; pid_t son; - module_initialized = 1; if (pipe(p) == -1) { perror("pipe"); exit(1); } + command_pipe_read = p[0]; command_pipe_write = p[1]; @@ -164,10 +175,11 @@ void start_background_system(void) perror("pipe"); exit(1); } + result_pipe_read = p[0]; result_pipe_write = p[1]; - son = fork(); + if (son == -1) { perror("fork"); exit(1); @@ -181,6 +193,56 @@ void start_background_system(void) close(result_pipe_read); close(command_pipe_write); - background_system_process(); } + + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority){ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + struct sched_param sparam={0}; + sparam.sched_priority = priority; + pthread_attr_setschedparam(&attr, &sparam); + + pthread_create(t, &attr, func, param); + + pthread_setname_np(*t, name); + if (affinity != -1 ) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(affinity, &cpuset); + AssertFatal( pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset) == 0, "Error setting processor affinity"); + } + + pthread_attr_destroy(&attr); +} + +// Block CPU C-states deep sleep +void configure_linux(void) { + int ret; + static int latency_target_fd=-1; + uint32_t latency_target_value=10; // in microseconds + if (latency_target_fd == -1) { + if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) { + ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value)); + if (ret == 0) { + printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno)); + close(latency_target_fd); + latency_target_fd=-1; + return; + } + } + } + if (latency_target_fd != -1) + LOG_I(HW,"# /dev/cpu_dma_latency set to %dus\n", latency_target_value); + else + LOG_E(HW,"Can't set /dev/cpu_dma_latency to %dus\n", latency_target_value); + + // Set CPU frequency to it's maximum + if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done")) + LOG_W(HW,"Can't set cpu frequency\n"); + +} diff --git a/common/utils/system.h b/common/utils/system.h index 658c17adc1a476ce68c03d1510623c87c382ab29..a89a6c5b1729f0b968fbfd4baed9cfd3cce85b10 100644 --- a/common/utils/system.h +++ b/common/utils/system.h @@ -21,6 +21,12 @@ #ifndef _SYSTEM_H_OAI_ #define _SYSTEM_H_OAI_ +#include <stdint.h> +#include <pthread.h> +#ifdef __cplusplus +extern "C" { +#endif + /**************************************************** * send a command to the background process @@ -36,4 +42,23 @@ int background_system(char *command); void start_background_system(void); +void set_latency_target(void); +void configure_linux(void); + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority); +#define OAI_PRIORITY_RT_LOW sched_get_priority_min(SCHED_FIFO) +#define OAI_PRIORITY_RT sched_get_priority_max(SCHED_FIFO)-10 +#define OAI_PRIORITY_RT_MAX sched_get_priority_max(SCHED_FIFO) + +void thread_top_init(char *thread_name, + int affinity, + uint64_t runtime, + uint64_t deadline, + uint64_t period); + +#ifdef __cplusplus +} +#endif + + #endif /* _SYSTEM_H_OAI_ */ diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 28dd38b65a1c2a9d803d1fae7813f109c409aa5a..801bc8d4dc6f891e83c2c7adf759f0e269c2a421 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -230,13 +230,11 @@ void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) { -void pdsch_procedures(PHY_VARS_eNB *eNB, +bool dlsch_procedures(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int harq_pid, LTE_eNB_DLSCH_t *dlsch, - LTE_eNB_DLSCH_t *dlsch1, - LTE_eNB_UE_stats *ue_stats, - int ra_flag) { + LTE_eNB_UE_stats *ue_stats) { int frame=proc->frame_tx; int subframe=proc->subframe_tx; LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; @@ -265,27 +263,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, dlsch_harq->round); } - MSC_LOG_TX_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u PDSCH/DLSCH input size = %"PRIu16", G %d, nb_rb %"PRIu16", TBS %"PRIu16", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")", - frame, subframe, - dlsch_harq->TBS/8, - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame, - subframe, - dlsch_harq->mimo_mode==TM7?7:0), - dlsch_harq->nb_rb, - dlsch_harq->TBS, - pmi2hex_2Ar1(dlsch_harq->pmi_alloc), - dlsch_harq->rvidx, - dlsch_harq->round); - if (ue_stats) ue_stats->dlsch_sliding_cnt++; if (dlsch_harq->round == 0) { @@ -300,15 +277,17 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, #endif } - if (dlsch->rnti!=0xffff) LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n", - dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0],dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round); + if (dlsch->rnti!=0xffff) + LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n", + dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0], + dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round); // 36-212 if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF if (dlsch_harq->pdu==NULL) { LOG_E(PHY,"dlsch_harq->pdu == NULL SFN/SF:%04d%d dlsch[rnti:%x] dlsch_harq[pdu:%p pdsch_start:%d Qm:%d Nl:%d round:%d nb_rb:%d rb_alloc[0]:%d]\n", frame,subframe,dlsch->rnti, dlsch_harq->pdu, dlsch_harq->pdsch_start,dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0]); - return; + return false; } start_meas(&eNB->dlsch_encoding_stats); @@ -330,44 +309,57 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, if(eNB->dlsch_encoding_stats.p_time>500*3000 && opp_enabled == 1) { print_meas_now(&eNB->dlsch_encoding_stats,"total coding",stderr); } - - // 36-211 - start_meas(&eNB->dlsch_scrambling_stats); - dlsch_scrambling(fp, - 0, - dlsch, - harq_pid, - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame,subframe, - 0), - 0, - frame, - subframe<<1); - stop_meas(&eNB->dlsch_scrambling_stats); - start_meas(&eNB->dlsch_modulation_stats); - dlsch_modulation(eNB, - eNB->common_vars.txdataF, - AMP, - frame, - subframe, - dlsch_harq->pdsch_start, - dlsch, - dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL); - stop_meas(&eNB->dlsch_modulation_stats); - } - #ifdef PHY_TX_THREAD - dlsch->active[subframe] = 0; + dlsch->active[subframe] = 0; #else - dlsch->active = 0; + dlsch->active = 0; #endif - dlsch_harq->round++; - LOG_D(PHY,"Generating DLSCH/PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round); + dlsch_harq->round++; + LOG_D(PHY,"Generated DLSCH dlsch_harq[round:%d]\n",dlsch_harq->round); + return true; + } + return false; +} + +void pdsch_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, + int harq_pid, + LTE_eNB_DLSCH_t *dlsch, + LTE_eNB_DLSCH_t *dlsch1) { + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + // 36-211 + start_meas(&eNB->dlsch_scrambling_stats); + dlsch_scrambling(fp, + 0, + dlsch, + harq_pid, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0), + 0, + frame, + subframe<<1); + stop_meas(&eNB->dlsch_scrambling_stats); + start_meas(&eNB->dlsch_modulation_stats); + dlsch_modulation(eNB, + eNB->common_vars.txdataF, + AMP, + frame, + subframe, + dlsch_harq->pdsch_start, + dlsch, + dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL); + stop_meas(&eNB->dlsch_modulation_stats); + + LOG_D(PHY,"Generated PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round); } @@ -531,14 +523,18 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, dlsch0->harq_ids[frame%2][6], dlsch0->harq_ids[frame%2][7]); } else { - // generate pdsch - pdsch_procedures(eNB, + if (dlsch_procedures(eNB, proc, harq_pid, dlsch0, - dlsch1, - &eNB->UE_stats[(uint32_t)UE_id], - 0); + &eNB->UE_stats[(uint32_t)UE_id])) { + // if we generate dlsch, we must generate pdsch + pdsch_procedures(eNB, + proc, + harq_pid, + dlsch0, + dlsch1); + } } } else if ((dlsch0)&&(dlsch0->rnti>0)&& #ifdef PHY_TX_THREAD diff --git a/openair1/SIMULATION/TOOLS/random_channel.c b/openair1/SIMULATION/TOOLS/random_channel.c index 8341c574da2968b8a361cdc82c3801bf8a91b998..f056d51b5d3c49a55a71e058ec2b061f2f911022 100644 --- a/openair1/SIMULATION/TOOLS/random_channel.c +++ b/openair1/SIMULATION/TOOLS/random_channel.c @@ -1204,6 +1204,10 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx, return(chan_desc); } +void free_channel_desc_scm(channel_desc_t * ch) { + // Must be made cleanly, a lot of leaks... + free(ch); +} int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index c1685e11ecd5beab3aeed890c8fee63a634132c1..010f54a3ba4e45d4203256388022dfa15f2a5dcf 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -105,7 +105,7 @@ int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_param if ( IS_SOFTMODEM_BASICSIM ) { libname=OAI_BASICSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; - } else if ( IS_SOFTMODEM_RFSIM ) { + } else if ( IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) { libname=OAI_RFSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; } else if (flag == RAU_LOCAL_RADIO_HEAD) { diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 3b23d6de066484a5e8d9f440f70fe1d1e9c1a545..d30848609628788682ce08c629b9ec18b633f2b6 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -47,8 +47,8 @@ pthread_mutex_t Sockmutex; typedef struct buffer_s { int conn_sock; - bool alreadyRead; - uint64_t lastReceivedTS; + openair0_timestamp lastReceivedTS; + openair0_timestamp lastWroteTS; bool headerMode; samplesBlockHeader_t th; char *transferPtr; @@ -60,7 +60,7 @@ typedef struct buffer_s { typedef struct { int listen_sock, epollfd; - uint64_t nextTimestamp; + openair0_timestamp nextTimestamp; uint64_t typeStamp; char *ip; int saveIQfile; @@ -104,9 +104,9 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si // Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ? // the parameter "-s" is declared as SNR, but the input power is not well defined // −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise) - const double rxGain= 132.24 - snr_dB; + const double rxGain= 132.24 - snr_dB; // sqrt(4*noise_figure_watt) is the thermal noise factor (volts) - // fixme: the last constant is pure trial results to make decent noise + // fixme: the last constant is pure trial results to make decent noise const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10; // Fixme: we don't fill the offset length samples at begining ? // anyway, in today code, channel_offset=0 @@ -135,9 +135,6 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si } out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0)); - printf("in: %d, out %d= %f*%f + %f*%f\n", - input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x, - pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0)); out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0)); out_ptr++; } @@ -156,8 +153,8 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) { AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, ""); ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; - ptr->alreadyRead=false; ptr->lastReceivedTS=0; + ptr->lastWroteTS=0; ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; ptr->remainToTransfer=sizeof(samplesBlockHeader_t); @@ -322,21 +319,22 @@ sin_addr: setblocking(sock, notBlocking); allocCirBuf(t, sock); - t->buf[sock].alreadyRead=true; // UE will start blocking on read return 0; } -uint64_t lastW=-1; int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { rfsimulator_state_t *t = device->priv; LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); + for (int i=0; i<FD_SETSIZE; i++) { - buffer_t *ptr=&t->buf[i]; + buffer_t *b=&t->buf[i]; - if (ptr->conn_sock >= 0 ) { + if (b->conn_sock >= 0 ) { + if ( abs((double)b->lastWroteTS-timestamp) > (double)CirSize) + LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp}; - fullwrite(ptr->conn_sock,&header, sizeof(header), t); + fullwrite(b->conn_sock,&header, sizeof(header), t); sample_t tmpSamples[nsamps][nbAnt]; for(int a=0; a<nbAnt; a++) { @@ -346,17 +344,17 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi tmpSamples[s][a]=in[s]; } - if (ptr->conn_sock >= 0 ) - fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); + if (b->conn_sock >= 0 ) { + fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); + b->lastWroteTS=timestamp+nsamps; + } } } - lastW=timestamp; LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); // Let's verify we don't have incoming data // This is mandatory when the opposite side don't transmit - // This is mandatory when the opposite side don't transmit flushInput(t, 0); pthread_mutex_unlock(&Sockmutex); return nsamps; @@ -428,7 +426,6 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { AssertFatal( (t->typeStamp == UE_MAGICDL_FDD && b->th.magic==ENB_MAGICDL_FDD) || (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol"); b->headerMode=false; - b->alreadyRead=true; if ( b->lastReceivedTS != b->th.timestamp) { int nbAnt= b->th.nbAnt; @@ -444,8 +441,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { } b->lastReceivedTS=b->th.timestamp; - AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize), - "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS); + AssertFatal(b->lastWroteTS == 0 || ( abs((double)b->lastWroteTS-b->lastReceivedTS) < (double)CirSize), + "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); } @@ -501,15 +498,33 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo return nsamps; } } else { + bool have_to_wait; do { have_to_wait=false; for ( int sock=0; sock<FD_SETSIZE; sock++) { - if ( t->buf[sock].circularBuf && t->buf[sock].alreadyRead ) - if ( t->buf[sock].lastReceivedTS == 0 || - (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { + buffer_t *b=&t->buf[sock]; + if ( b->circularBuf) { + LOG_D(HW,"sock: %d, lastWroteTS: %lu, lastRecvTS: %lu, TS must be avail: %lu\n", + sock, b->lastWroteTS, + b->lastReceivedTS, + t->nextTimestamp+nsamps); + if ( b->lastReceivedTS > b->lastWroteTS ) { + // The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance + // This occurs for example when UE is in sync mode: it doesn't transmit + // with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power + struct complex16 v={0}; + void *samplesVoid[b->th.nbAnt]; + for ( int i=0; i <b->th.nbAnt; i++) + samplesVoid[i]=(void*)&v; + rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0); + } + } + + if ( b->circularBuf ) + if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) { have_to_wait=true; break; } @@ -532,7 +547,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for (int sock=0; sock<FD_SETSIZE; sock++) { buffer_t *ptr=&t->buf[sock]; - if ( ptr->circularBuf && ptr->alreadyRead ) { + if ( ptr->circularBuf ) { bool reGenerateChannel=false; //fixme: when do we regenerate