diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c new file mode 100644 index 0000000000..4eae805eb7 --- /dev/null +++ b/executables/dl_fs6.c @@ -0,0 +1,229 @@ +#define MTU 65536 +#define UDP_TIMEOUT 100000L // in nano second + +receiveSubFrame(int sock) { + //read all subframe data from the control unit + char * buf[MTU]; + int ret=recv(sock, buf, sizeof(buf), 0); + if ( ret==-1) { + if ( errno == EWOULDBLOCK || errno== EINTR ) { + finishSubframeRecv(); + } else { + LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); + return; + } + } else { + } + +} + +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, + LTE_eNB_UE_stats *ue_stats, + int ra_flag) { + + 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-212 + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF + + // Replace dlsch_encoding + // data is in + // dlsch->harq_processes[harq_pid]->e + feedDlschBuffers(eNB, + dlsch_harq->pdu, + dlsch_harq->pdsch_start, + dlsch, + frame, + subframe, + &eNB->dlsch_rate_matching_stats, + &eNB->dlsch_turbo_encoding_stats, + &eNB->dlsch_turbo_encoding_waiting_stats, + &eNB->dlsch_turbo_encoding_main_stats, + &eNB->dlsch_turbo_encoding_wakeup_stats0, + &eNB->dlsch_turbo_encoding_wakeup_stats1, + &eNB->dlsch_interleaving_stats); + + // 36-211 + 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); + 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); + } + + dlsch->active = 0; + dlsch_harq->round++; +} + +phy_procedures_eNB_TX_fs6() { + + receiveSubFrame(); + + // We got + // subframe number + // + + for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { + memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], + 0, + fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); + } + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + if (is_pmch_subframe(frame,subframe,fp)) { + pmch_procedures(eNB,proc); + } else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); + } + } + + if (ul_subframe < 10)if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + for (i=0; i= MAKE_VERSION(14, 0, 0)) + + if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; + else +#endif + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + + if (eNB->ulsch[i]) { + ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + } + } + } + + num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; + num_dci = eNB->pdcch_vars[subframe&1].num_dci; + if (num_dci > 0) + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + generate_dci_top(num_pdcch_symbols, + num_dci, + &eNB->pdcch_vars[subframe&1].dci_alloc[0], + 0, + AMP, + fp, + eNB->common_vars.txdataF, + subframe); + num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; + + if (num_mdci > 0) { + generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); + } + } + + // Now scan UE specific DLSCH + LTE_eNB_DLSCH_t *dlsch0,*dlsch1; + + for (UE_id=0; UE_iddlsch[(uint8_t)UE_id][0]; + dlsch1 = eNB->dlsch[(uint8_t)UE_id][1]; + + if ((dlsch0)&&(dlsch0->rnti>0)&& + (dlsch0->active == 1) + ) { + // get harq_pid + harq_pid = dlsch0->harq_ids[frame%2][subframe]; + AssertFatal(harq_pid>=0,"harq_pid is negative\n"); + + if (harq_pid>=8) { + if (dlsch0->ue_type==0) + LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x \n", + harq_pid,UE_id,frame,subframe,dlsch0->rnti); + } else { + // generate pdsch + pdsch_procedures_fs6(eNB, + proc, + harq_pid, + dlsch0, + dlsch1, + &eNB->UE_stats[(uint32_t)UE_id], + 0); + } + } else if ((dlsch0)&&(dlsch0->rnti>0)&& + (dlsch0->active == 0) + ) { + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + dlsch0->subframe_tx[subframe]=0; + } + } + generate_phich_top(eNB, + proc, + AMP); + +} + +DL_thread_fs6() { + receiveSubFrame(); + phy_procedures_eNB_TX_fs6(); + ru->feptx_prec(ru); + ru->feptx_ofdm(ru); + ru->fh_south_out(ru); +} + +int createListner (port) { + int sock; + AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); + struct sockaddr_in addr = { +sin_family: + AF_INET, +sin_port: +htons(port), +sin_addr: + { s_addr: INADDR_ANY } + }; + AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); + struct timeval tv={0,UDP_TIMEOUT}; + AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); +} + + +DL_thread_frequency() { + frequency_t header; + + full_read(&header, diff --git a/executables/split_headers.h b/executables/split_headers.h new file mode 100644 index 0000000000..7a580affd4 --- /dev/null +++ b/executables/split_headers.h @@ -0,0 +1,13 @@ +#ifndef __SPLIT_HEADERS_H +#define __SPLIT_HEADERS_H + +struct frequency_s { + int frame; + int subframe; + int timestamp; + int sampleSize; + int nbAnt + int nbSamples; +} frequency_t; + +#endif diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 3b3b9336d4..9a209f06a5 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -431,7 +431,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; - else + else #endif harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 588a96ca6d..d05ffbd8fa 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -1354,7 +1354,7 @@ int main(int argc, char **argv) { printStatIndent2(&eNB->ulsch_deinterleaving_stats,"sub-block interleaving" ); printStatIndent2(&eNB->ulsch_demultiplexing_stats,"sub-block demultiplexing" ); printStatIndent2(&eNB->ulsch_rate_unmatching_stats,"sub-block rate-matching" ); - printf("|__ turbo_decoder(%d bits), avg iterations: %.1f %.2f us (%d cycles, %d trials)\n", + printf(" |__ turbo_decoder(%d bits), avg iterations: %.1f %.2f us (%d cycles, %d trials)\n", eNB->ulsch[0]->harq_processes[harq_pid]->Cminus ? eNB->ulsch[0]->harq_processes[harq_pid]->Kminus : eNB->ulsch[0]->harq_processes[harq_pid]->Kplus, diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index 3f81816aa1..23c979a6e1 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/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 0af6fa9c5e..03fe4fb789 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -102,6 +102,10 @@ typedef enum { IRIS_DEV, /*!\brief device is NONE*/ NONE_DEV, + /*!\brief device is ADRV9371_ZC706 */ + ADRV9371_ZC706_DEV, + /*!\brief device is UEDv2 */ + UEDv2_DEV, MAX_RF_DEV_TYPE } dev_type_t; @@ -214,6 +218,14 @@ typedef struct { int iq_rxrescale; //! Configuration file for LMS7002M char *configFilename; + //! remote IP/MAC addr for Ethernet interface + char *remote_addr; + //! remote port number for Ethernet interface + unsigned int remote_port; + //! local IP/MAC addr for Ethernet interface (eNB/BBU, UE) + char *my_addr; + //! local port number for Ethernet interface (eNB/BBU, UE) + unsigned int my_port; #if defined(USRP_REC_PLAY) unsigned short sf_mode; // 1=record, 2=replay char sf_filename[1024]; // subframes file path @@ -223,6 +235,13 @@ typedef struct { unsigned int sf_write_delay; // write delay in replay mode unsigned int eth_mtu; // ethernet MTU #endif + + //! number of samples per tti + unsigned int samples_per_tti; + //! the sample rate for receive. + double rx_sample_rate; + //! the sample rate for transmit. + double tx_sample_rate; } openair0_config_t; /*! \brief RF mapping */ @@ -384,6 +403,31 @@ struct openair0_device_t { typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg); /* type of transport init function, implemented in shared lib */ typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params); +#define UE_MAGICDL_FDD 0xA5A5A5A5A5A5A5A5 // UE DL FDD record +#define UE_MAGICUL_FDD 0x5A5A5A5A5A5A5A5A // UE UL FDD record +#define UE_MAGICDL_TDD 0xA6A6A6A6A6A6A6A6 // UE DL TDD record +#define UE_MAGICUL_TDD 0x6A6A6A6A6A6A6A6A // UE UL TDD record + +#define ENB_MAGICDL_FDD 0xB5B5B5B5B5B5B5B5 // eNB DL FDD record +#define ENB_MAGICUL_FDD 0x5B5B5B5B5B5B5B5B // eNB UL FDD record +#define ENB_MAGICDL_TDD 0xB6B6B6B6B6B6B6B6 // eNB DL TDD record +#define ENB_MAGICUL_TDD 0x6B6B6B6B6B6B6B6B // eNB UL TDD record + +#define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size) + +#define sample_t uint32_t // 2*16 bits complex number + +typedef struct { + uint64_t magic; // Magic value (see defines above) + uint32_t size; // Number of samples per antenna to follow this header + uint32_t nbAnt; // Total number of antennas following this header + // Samples per antenna follow this header, + // i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1 + // data following this header in bytes is nbAnt*size*sizeof(sample_t) + uint64_t timestamp; // Timestamp value of first sample + uint32_t option_value; // Option value + uint32_t option_flag; // Option flag +} samplesBlockHeader_t; #ifdef __cplusplus extern "C" @@ -408,7 +452,7 @@ openair0_timestamp get_usrp_time(openair0_device *device); * \returns 0 in success */ int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg); - +#define gettid() syscall(__NR_gettid) /*@}*/ #ifdef __cplusplus diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index a17327b03e..21d3d5dc7e 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -24,28 +24,23 @@ #define PORT 4043 //TCP port for this simulator #define CirSize 3072000 // 100ms is enough +#define MaxBlock 30000 #define sample_t uint32_t // 2*16 bits complex number #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t)) #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) -#define MAGICeNB 0xA5A5A5A5A5A5A5A5 -#define MAGICUE 0x5A5A5A5A5A5A5A5A -typedef struct { - uint64_t magic; - uint32_t size; - uint32_t nbAnt; - uint64_t timestamp; -} transferHeader; +#define sample_t uint32_t // 2*16 bits complex number typedef struct buffer_s { int conn_sock; - bool alreadyRead; + bool readEnabled; uint64_t lastReceivedTS; + uint64_t lastWroteTS; bool headerMode; - transferHeader th; + samplesBlockHeader_t th; char *transferPtr; uint64_t remainToTransfer; - char *circularBufEnd; + int nbAnt; sample_t *circularBuf; } buffer_t; @@ -55,19 +50,22 @@ typedef struct { uint64_t typeStamp; uint64_t initialAhead; char *ip; + int saveIQfile; buffer_t buf[FD_SETSIZE]; } rfsimulator_state_t; void allocCirBuf(rfsimulator_state_t *bridge, int sock) { buffer_t *ptr=&bridge->buf[sock]; AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, ""); - ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; - ptr->remainToTransfer=sizeof(transferHeader); + ptr->remainToTransfer=sizeof(samplesBlockHeader_t); int sendbuff=1000*1000*10; AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); + int tcp_maxseg = 1400; + AssertFatal ( setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,sizeof(tcp_maxseg)) == 0, ""); struct epoll_event ev= {0}; ev.events = EPOLLIN | EPOLLRDHUP; ev.data.fd = sock; @@ -87,7 +85,7 @@ void socketError(rfsimulator_state_t *bridge, int sock) { LOG_W(HW,"Lost socket \n"); removeCirBuf(bridge, sock); - if (bridge->typeStamp==MAGICUE) + if (bridge->typeStamp==UE_MAGICDL_FDD) exit(1); } } @@ -120,6 +118,11 @@ void setblocking(int sock, enum blocking_t active) { static bool flushInput(rfsimulator_state_t *t); void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { + if (t->saveIQfile != -1) { + if (write(t->saveIQfile, _buf, count) != count ) + LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno)); + } + char *buf = _buf; int l; setblocking(fd, notBlocking); @@ -145,7 +148,7 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { int server_start(openair0_device *device) { rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; - t->typeStamp=MAGICeNB; + t->typeStamp=ENB_MAGICDL_FDD; AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); int enable = 1; AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, ""); @@ -168,7 +171,7 @@ sin_addr: int start_ue(openair0_device *device) { rfsimulator_state_t *t = device->priv; - t->typeStamp=MAGICUE; + t->typeStamp=UE_MAGICDL_FDD; int sock; AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); struct sockaddr_in addr = { @@ -196,43 +199,104 @@ sin_addr: setblocking(sock, notBlocking); allocCirBuf(t, sock); - t->buf[sock].alreadyRead=true; // UE will start blocking on read + t->buf[sock].readEnabled=true; // UE will start blocking on read return 0; } +uint64_t lwrote; int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { rfsimulator_state_t *t = device->priv; + // We do small blocks because the UE and the eNB are not aligned + // So large blocks can lead to deadlock (each side waits a incoming block completed) + int curBeg=0; - for (int i=0; ibuf[i]; + do { + int sizeToSend=min(nsamps-curBeg,MaxBlock); - if (ptr->conn_sock >= 0 ) { - transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp}; - fullwrite(ptr->conn_sock,&header, sizeof(header), t); - sample_t tmpSamples[nsamps][nbAnt]; + for (int i=0; ibuf[i]; - for(int a=0; aconn_sock >= 0 ) { + samplesBlockHeader_t header= {t->typeStamp, sizeToSend, nbAnt, timestamp+curBeg}; + fullwrite(ptr->conn_sock,&header, sizeof(header), t); + sample_t tmpSamples[sizeToSend][nbAnt]; - for(int s=0; sconn_sock >= 0 ) { + fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(sizeToSend,nbAnt), t); + ptr->lastWroteTS=timestamp+curBeg+sizeToSend; + } } - - if (ptr->conn_sock >= 0 ) - fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); } - } - 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) ); + LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", + sizeToSend, timestamp+curBeg, timestamp+curBeg+sizeToSend, + signal_energy(samplesVoid[0]+curBeg, sizeToSend) ); + curBeg+=sizeToSend; + } while ( curBeg < nsamps ) ; + return nsamps; } +static void oneTransferDone(rfsimulator_state_t *t, buffer_t *b) { + // check the header and start block transfer + if ( b->headerMode==true) { + 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; + + if ( b->lastReceivedTS != b->th.timestamp && b->readEnabled && b->lastReceivedTS ) { + int nbAnt= b->th.nbAnt; + + for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) + for (int a=0; a < nbAnt; a++) + b->circularBuf[(index*nbAnt+a)%CirSize]=0; + + LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); + } + + if ( b->readEnabled && b->lastReceivedTS && b->lastWroteTS) + AssertFatal( fabs((double)b->lastReceivedTS - (double)b->lastWroteTS) < (double)CirSize, + "Difference between Rx/Tx timestamps impossible, Rx: %lu, T:%lu\n", + b->lastReceivedTS, b->lastWroteTS); + else + printf("diff: %f\n", abs((double)b->lastReceivedTS - (double)b->lastWroteTS)/1000.0); + + + b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; + b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); + } else { + LOG_I(HW,"Completed block reception: %ld\n", b->lastReceivedTS); + // in NB case, the UE started to write, since this event, we will wait it's data + // This is needed because the UE doesn't write in initial sync mode + // in UE case, the UE is already in this state (at connection time) + b->readEnabled=true; + b->lastReceivedTS=b->th.timestamp+b->th.size; + + // First block in UE, resync with the eNB current TS + if ( t->nextTimestamp == 0 ) { + t->nextTimestamp=b->lastReceivedTS-b->th.size; + LOG_I(HW,"Ue synchro on NB timestamp: %lu\n", t->nextTimestamp); + } + + b->headerMode=true; + b->transferPtr=(char *)&b->th; + b->remainToTransfer=sizeof(samplesBlockHeader_t); + b->th.magic=-1; + } +} + static bool flushInput(rfsimulator_state_t *t) { // Process all incoming events on sockets // store the data in lists struct epoll_event events[FD_SETSIZE]= {0}; - int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200); + int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 2); if ( nfds==-1 ) { if ( errno==EINTR || errno==EAGAIN ) @@ -264,13 +328,14 @@ static bool flushInput(rfsimulator_state_t *t) { } int blockSz; + char * circularBufEnd=((char *)b->circularBuf)+sampleToByte(CirSize,1); if ( b->headerMode) blockSz=b->remainToTransfer; else - blockSz= b->transferPtr+b->remainToTransfer < b->circularBufEnd ? + blockSz= b->transferPtr+b->remainToTransfer < circularBufEnd ? b->remainToTransfer : - b->circularBufEnd - 1 - b->transferPtr ; + circularBufEnd - 1 - b->transferPtr ; int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT); @@ -285,46 +350,11 @@ static bool flushInput(rfsimulator_state_t *t) { AssertFatal((b->remainToTransfer-=sz) >= 0, ""); b->transferPtr+=sz; - if (b->transferPtr==b->circularBufEnd - 1) + if (b->transferPtr==circularBufEnd - 1) b->transferPtr=(char *)b->circularBuf; - // check the header and start block transfer - if ( b->headerMode==true && b->remainToTransfer==0) { - AssertFatal( (t->typeStamp == MAGICUE && b->th.magic==MAGICeNB) || - (t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol"); - b->headerMode=false; - b->alreadyRead=true; - - if ( b->lastReceivedTS != b->th.timestamp) { - int nbAnt= b->th.nbAnt; - - for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) - for (int a=0; a < nbAnt; a++) - b->circularBuf[(index*nbAnt+a)%CirSize]=0; - - LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); - } - - b->lastReceivedTS=b->th.timestamp; - b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; - b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); - } - - if ( b->headerMode==false ) { - b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); - - if ( b->remainToTransfer==0) { - LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS); - - // First block in UE, resync with the eNB current TS - if ( t->nextTimestamp == 0 ) - t->nextTimestamp=b->lastReceivedTS-b->th.size; - - b->headerMode=true; - b->transferPtr=(char *)&b->th; - b->remainToTransfer=sizeof(transferHeader); - b->th.magic=-1; - } + if ( b->remainToTransfer==0) { + oneTransferDone(t,b); } } } @@ -367,7 +397,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for ( int sock=0; sockbuf[sock].circularBuf && - t->buf[sock].alreadyRead && //>= t->initialAhead && + t->buf[sock].readEnabled && (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { have_to_wait=true; break; @@ -390,7 +420,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for (int sock=0; sockbuf[sock]; - if ( ptr->circularBuf && ptr->alreadyRead ) { + if ( ptr->circularBuf && ptr->readEnabled ) { for (int a=0; aip=getenv("RFSIMULATOR")) == NULL ) { @@ -447,10 +477,22 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { } rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ? - MAGICeNB: - MAGICUE; - LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE"); - device->trx_start_func = rfsimulator->typeStamp == MAGICeNB ? + ENB_MAGICDL_FDD: + UE_MAGICDL_FDD; + LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "eNB" : "UE"); + char *saveF; + + if ((saveF=getenv("saveIQfile")) != NULL) { + rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666); + + if ( rfsimulator->saveIQfile != -1 ) + LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF); + else + LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno)); + } else + rfsimulator->saveIQfile = -1; + + device->trx_start_func = rfsimulator->typeStamp == ENB_MAGICDL_FDD ? server_start : start_ue; device->trx_get_stats_func = rfsimulator_get_stats; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 93a2440b94..9d2fd5d084 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -148,7 +148,7 @@ int attach_rru(RU_t *ru) { RRU_CONFIG_msg_t rru_config_msg; int received_capabilities=0; wait_eNBs(); - + LOG_ENTER(PHY); // Wait for capabilities while (received_capabilities==0) { memset((void *)&rru_config_msg,0,sizeof(rru_config_msg)); @@ -208,7 +208,7 @@ int connect_rau(RU_t *ru) { RRU_capabilities_t *cap; int i; int len; - + LOG_ENTER(PHY); // wait for RAU_tick while (tick_received == 0) { msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; @@ -299,7 +299,7 @@ int connect_rau(RU_t *ru) { // southbound IF5 fronthaul for 16-bit OAI format static inline void fh_if5_south_out(RU_t *ru) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); - + LOG_ENTER(PHY); send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_RRH_GW_DL); } @@ -315,7 +315,7 @@ static inline void fh_if4p5_south_out(RU_t *ru) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx); - + LOG_ENTER(PHY); if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT); } @@ -327,6 +327,7 @@ static inline void fh_if4p5_south_out(RU_t *ru) { void fh_if5_south_in(RU_t *ru,int *frame, int *subframe) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; RU_proc_t *proc = &ru->proc; + LOG_ENTER(PHY); recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; @@ -358,14 +359,14 @@ void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { uint16_t packet_type; uint32_t symbol_number=0; uint32_t symbol_mask_full; - + LOG_ENTER(PHY); if ((fp->frame_type == TDD) && (subframe_select(fp,*subframe)==SF_S)) symbol_mask_full = (1<ul_symbols_in_S_subframe)-1; else symbol_mask_full = (1<symbols_per_tti)-1; AssertFatal(proc->symbol_mask[*subframe]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*subframe,proc->symbol_mask[*subframe]); - + LOG_D(PHY,"start rcv IF4p5 \n"); do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number); @@ -382,6 +383,7 @@ void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]); } while(proc->symbol_mask[*subframe] != symbol_mask_full); + LOG_D(PHY,"Done rcv IF4p5 \n"); //caculate timestamp_rx, timestamp_tx based on frame and subframe proc->subframe_rx = sf; @@ -482,6 +484,7 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) { symbol_mask = (1<symbols_per_tti)-1; prach_rx = 0; + LOG_D(PHY,"start rcv IF4p5 \n"); do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number); @@ -578,6 +581,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { uint16_t packet_type; uint32_t symbol_number,symbol_mask,symbol_mask_full; int subframe_tx,frame_tx; + LOG_ENTER(PHY); LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); symbol_number = 0; symbol_mask = 0; @@ -643,7 +647,7 @@ void fh_if4p5_north_out(RU_t *ru) { RU_proc_t *proc=&ru->proc; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; const int subframe = proc->subframe_rx; - + LOG_ENTER(PHY); if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx ); if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { @@ -712,6 +716,8 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { unsigned int rxs; int i; openair0_timestamp ts=0,old_ts=0; + LOG_ENTER(PHY); + LOG_D(PHY,"%s:%d start rx_rf \n", __FILE__,__LINE__); for (i=0; inb_rx; i++) rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; @@ -820,6 +826,7 @@ void tx_rf(RU_t *ru) { lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); int sf_extension = 0; + LOG_D(PHY,"start tx_rf \n"); if ((SF_type == SF_DL) || (SF_type == SF_S)) { @@ -935,6 +942,7 @@ static void *ru_thread_asynch_rxtx( void *param ) { printf( "devices ok (ru_thread_asynch_rx)\n"); while (!oai_exit) { + LOG_ENTER(PHY); if (oai_exit) break; if (subframe==9) { @@ -968,7 +976,7 @@ void wakeup_slaves(RU_proc_t *proc) { struct timespec wait; wait.tv_sec=0; wait.tv_nsec=5000000L; - + LOG_ENTER(PHY); for (i=0; inum_slaves; i++) { RU_proc_t *slave_proc = proc->slave_proc[i]; @@ -1029,7 +1037,7 @@ static void *ru_thread_prach( void *param ) { if (oai_exit) break; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); - + LOG_ENTER(PHY); if (ru->eNB_list[0]) { prach_procedures( ru->eNB_list[0] @@ -1075,7 +1083,7 @@ static void *ru_thread_prach_br( void *param ) { if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break; if (oai_exit) break; - + LOG_ENTER(PHY); rx_prach(NULL, ru, NULL, @@ -1098,7 +1106,7 @@ int wakeup_synch(RU_t *ru) { struct timespec wait; wait.tv_sec=0; wait.tv_nsec=5000000L; - + LOG_ENTER(PHY); // wake up synch thread // lock the synch mutex and make sure the thread is ready if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) { @@ -1135,7 +1143,7 @@ void do_ru_synch(RU_t *ru) { double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0]; double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0]; - + LOG_ENTER(PHY); for (i=0; i<4; i++) { ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i]; ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1; @@ -1198,7 +1206,7 @@ void wakeup_L1s(RU_t *ru) { int i; PHY_VARS_eNB **eNB_list = ru->eNB_list; LOG_D(PHY,"wakeup_L1s (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); - + LOG_ENTER(PHY); if (ru->num_eNB==1 && ru->eNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { // call eNB function directly char string[20]; @@ -1496,7 +1504,7 @@ static void *ru_thread_tx( void *param ) { wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx"); if (oai_exit) break; - + LOG_ENTER(PHY); // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) ru->feptx_prec(ru); @@ -1644,7 +1652,7 @@ static void *ru_thread( void *param ) { // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,sched_getcpu()); - + LOG_ENTER(PHY); // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. // They are set on the first rx/tx in the underly FH routines. if (subframe==9) {