diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c9741ce4884ed7a0918fe8d84066cc2a2fcdae9f..10f263100b884e852da089ed946b4f3467b99722 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2090,9 +2090,9 @@ target_link_libraries (lte-softmodem -Wl,--end-group z dl) -add_executable(simple-softmodem +add_executable(ocp-softmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_DIR}/executables/simple_main.c + ${OPENAIR_DIR}/executables/main-ocp.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c @@ -2113,15 +2113,15 @@ add_executable(simple-softmodem ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} ) -add_dependencies(simple-softmodem rrc_flag s1ap_flag x2_flag) +add_dependencies(ocp-softmodem rrc_flag s1ap_flag x2_flag) -target_link_libraries (simple-softmodem +target_link_libraries (ocp-softmodem -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7 NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) -target_link_libraries (simple-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) +target_link_libraries (ocp-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) add_executable(cu_test ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c diff --git a/executables/simple_main.c b/executables/main-ocp.c similarity index 95% rename from executables/simple_main.c rename to executables/main-ocp.c index 7a15f6df3caab88cf8ec2bc5f3f7e7eaaaab6d5c..b3472f17cb27f94e5afa451de3d53bfee732f64b 100644 --- a/executables/simple_main.c +++ b/executables/main-ocp.c @@ -50,9 +50,6 @@ void init_eNB_proc(int inst) { proc->CC_id = CC_id; proc->first_rx =1; proc->first_tx =1; - proc->RU_mask_tx = (1<<eNB->num_RU)-1; - proc->RU_mask =0; - proc->RU_mask_prach =0; pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); pthread_mutex_init( &L1_proc->mutex, NULL); pthread_cond_init( &L1_proc->cond, NULL); @@ -94,102 +91,12 @@ void init_RU_proc(RU_t *ru) { for (i=0; i<10; i++) proc->symbol_mask[i]=0; pthread_mutex_init( &proc->mutex_synch,NULL); - pthread_cond_init( &proc->cond_synch,NULL); pthread_cond_init( &proc->cond_eNBs, NULL); - pthread_t t; threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); } -void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - // set timing for prach thread - proc->frame_prach = frame; - proc->subframe_prach = subframe; - prach_procedures(eNB,0); - } -} - -void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); - // set timing for prach thread - proc->frame_prach_br = frame; - proc->subframe_prach_br = subframe; - prach_procedures(eNB,1); - } -} - -static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { - - AssertFatal( eNB !=NULL, ""); - - if (NFAPI_MODE==NFAPI_MODE_PNF) { - // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick - //add_subframe(&frame, &subframe, 4); - //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); - oai_subframe_ind(proc->frame_rx, proc->subframe_rx); - } - - AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && - eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); - - wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); - wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); - release_UE_in_freeList(eNB->Mod_id); - - // UE-specific RX processing for subframe n - if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX(eNB, proc); - } - - pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.frame = proc->frame_rx; - eNB->UL_INFO.subframe = proc->subframe_rx; - eNB->UL_INFO.module_id = eNB->Mod_id; - eNB->UL_INFO.CC_id = eNB->CC_id; - eNB->if_inst->UL_indication(&eNB->UL_INFO); - pthread_mutex_unlock(&eNB->UL_INFO_mutex); - phy_procedures_eNB_TX(eNB, proc, 1); - - return(0); -} - -void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { - L1_proc_t *proc = &eNB->proc; - L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - RU_proc_t *ru_proc=&ru->proc; - proc->frame_rx = frame_rx; - proc->subframe_rx = subframe_rx; - - if (!oai_exit) { - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); - L1_proc->frame_rx = ru_proc->frame_rx; - L1_proc->subframe_rx = ru_proc->subframe_rx; - L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? - (L1_proc->frame_rx+1)&1023 : - L1_proc->frame_rx; - L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; - - if (rxtx(eNB,L1_proc,string) < 0) - LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; - } -} - void init_transport(PHY_VARS_eNB *eNB) { int i; int j; @@ -354,129 +261,6 @@ void stop_eNB(int nb_inst) { kill_eNB_proc(inst); } } - -void rx_rf(RU_t *ru,int *frame,int *subframe) { - RU_proc_t *proc = &ru->proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - void *rxp[ru->nb_rx]; - unsigned int rxs; - int i; - openair0_timestamp ts=0,old_ts=0; - - for (i=0; i<ru->nb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; - - old_ts = proc->timestamp_rx; - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - fp->samples_per_tti, - ru->nb_rx); - proc->timestamp_rx = ts-ru->ts_offset; - - // AssertFatal(rxs == fp->samples_per_tti, - // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); - if(rxs != fp->samples_per_tti) { - LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); - } - - if (proc->first_rx == 1) { - ru->ts_offset = proc->timestamp_rx; - proc->timestamp_rx = 0; - } else { - if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { - ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); - proc->timestamp_rx = ts-ru->ts_offset; - } - } - - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; - proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; - // synchronize first reception to frame 0 subframe 0 - proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); - proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; - proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - - if (proc->first_rx == 0) { - AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame , - "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n", - (long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame); - } else { - proc->first_rx = 0; - *frame = proc->frame_rx; - *subframe = proc->subframe_rx; - } - - if (rxs != fp->samples_per_tti) { -#if defined(USRP_REC_PLAY) - exit_fun("Exiting IQ record/playback"); -#else - //exit_fun( "problem receiving samples" ); - LOG_E(PHY, "problem receiving samples"); -#endif - } -} - -void tx_rf(RU_t *ru) { - RU_proc_t *proc = &ru->proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - void *txp[ru->nb_tx]; - int i; - 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; - - if ((SF_type == SF_DL) || - (SF_type == SF_S)) { - int siglen=fp->samples_per_tti,flags=1; - - if (SF_type == SF_S) { - /* end_of_burst_delay is used to stop TX only "after a while". - * If we stop right after effective signal, with USRP B210 and - * B200mini, we observe a high EVM on the S subframe (on the - * PSS). - * A value of 400 (for 30.72MHz) solves this issue. This is - * the default. - */ - siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) - + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples) - + ru->end_of_burst_delay; - flags=3; // end of burst - } - - if (fp->frame_type == TDD && - SF_type == SF_DL && - prevSF_type == SF_UL) { - flags = 2; // start of burst - sf_extension = ru->sf_extension; - } - -#if defined(__x86_64) || defined(__i386__) -#ifdef __AVX2__ - sf_extension = (sf_extension)&0xfffffff8; -#else - sf_extension = (sf_extension)&0xfffffffc; -#endif -#elif defined(__arm__) - sf_extension = (sf_extension)&0xfffffffc; -#endif - - for (i=0; i<ru->nb_tx; i++) - txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; - - /* add fail safe for late command end */ - // prepare tx buffer pointers - ru->rfdevice.trx_write_func(&ru->rfdevice, - proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, - txp, - siglen+sf_extension, - ru->nb_tx, - flags); - LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, - (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); - } -} - // this is for RU with local RF unit void fill_rf_config(RU_t *ru, char *rf_config_file) { int i; @@ -642,6 +426,247 @@ int setup_RU_buffers(RU_t *ru) { return(0); } + +void init_precoding_weights(PHY_VARS_eNB *eNB) { + int layer,ru_id,aa,re,ue,tb; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + RU_t *ru; + LTE_eNB_DLSCH_t *dlsch; + + // init precoding weigths + for (ue=0; ue<NUMBER_OF_UE_MAX; ue++) { + for (tb=0; tb<2; tb++) { + dlsch = eNB->dlsch[ue][tb]; + + for (layer=0; layer<4; layer++) { + int nb_tx=0; + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + ru = RC.ru[ru_id]; + nb_tx+=ru->nb_tx; + } + + dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *)); + + for (aa=0; aa<nb_tx; aa++) { + dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); + + for (re=0; re<fp->ofdm_symbol_size; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } + } +} + +void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + prach_procedures(eNB,0); + } +} + +void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); + // set timing for prach thread + proc->frame_prach_br = frame; + proc->subframe_prach_br = subframe; + prach_procedures(eNB,1); + } +} + +static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { + AssertFatal( eNB !=NULL, ""); + + if (NFAPI_MODE==NFAPI_MODE_PNF) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + oai_subframe_ind(proc->frame_rx, proc->subframe_rx); + } + + AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && + eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); + wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); + wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); + release_UE_in_freeList(eNB->Mod_id); + + // UE-specific RX processing for subframe n + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + phy_procedures_eNB_uespec_RX(eNB, proc); + } + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.frame = proc->frame_rx; + eNB->UL_INFO.subframe = proc->subframe_rx; + eNB->UL_INFO.module_id = eNB->Mod_id; + eNB->UL_INFO.CC_id = eNB->CC_id; + eNB->if_inst->UL_indication(&eNB->UL_INFO); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + phy_procedures_eNB_TX(eNB, proc, 1); + return(0); +} + +void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *ru_proc=&ru->proc; + proc->frame_rx = frame_rx; + proc->subframe_rx = subframe_rx; + + if (!oai_exit) { + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->subframe_rx = ru_proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? + (L1_proc->frame_rx+1)&1023 : + L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; + + if (rxtx(eNB,L1_proc,string) < 0) + LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); + + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + } +} + +void rx_rf(RU_t *ru,int *frame,int *subframe) { + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *rxp[ru->nb_rx]; + unsigned int rxs; + int i; + openair0_timestamp ts=0,old_ts=0; + + for (i=0; i<ru->nb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; + + old_ts = proc->timestamp_rx; + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &ts, + rxp, + fp->samples_per_tti, + ru->nb_rx); + proc->timestamp_rx = ts-ru->ts_offset; + + // AssertFatal(rxs == fp->samples_per_tti, + // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + if(rxs != fp->samples_per_tti) { + LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + } + + if (proc->first_rx == 1) { + ru->ts_offset = proc->timestamp_rx; + proc->timestamp_rx = 0; + } else { + if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { + ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + proc->timestamp_rx = ts-ru->ts_offset; + } + } + + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; + proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; + // synchronize first reception to frame 0 subframe 0 + proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); + proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + + if (proc->first_rx == 0) { + AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame, + "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n", + (long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame); + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + if (rxs != fp->samples_per_tti) { +#if defined(USRP_REC_PLAY) + exit_fun("Exiting IQ record/playback"); +#else + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); +#endif + } +} + +void tx_rf(RU_t *ru) { + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *txp[ru->nb_tx]; + int i; + 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; + + if ((SF_type == SF_DL) || + (SF_type == SF_S)) { + int siglen=fp->samples_per_tti,flags=1; + + if (SF_type == SF_S) { + /* end_of_burst_delay is used to stop TX only "after a while". + * If we stop right after effective signal, with USRP B210 and + * B200mini, we observe a high EVM on the S subframe (on the + * PSS). + * A value of 400 (for 30.72MHz) solves this issue. This is + * the default. + */ + siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples) + + ru->end_of_burst_delay; + flags=3; // end of burst + } + + if (fp->frame_type == TDD && + SF_type == SF_DL && + prevSF_type == SF_UL) { + flags = 2; // start of burst + sf_extension = ru->sf_extension; + } + +#if defined(__x86_64) || defined(__i386__) +#ifdef __AVX2__ + sf_extension = (sf_extension)&0xfffffff8; +#else + sf_extension = (sf_extension)&0xfffffffc; +#endif +#elif defined(__arm__) + sf_extension = (sf_extension)&0xfffffffc; +#endif + + for (i=0; i<ru->nb_tx; i++) + txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; + + /* add fail safe for late command end */ + // prepare tx buffer pointers + ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + } +} + static void *ru_thread( void *param ) { static int ru_thread_status; RU_t *ru = (RU_t *)param; @@ -664,10 +689,6 @@ static void *ru_thread( void *param ) { } LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); - pthread_mutex_lock(&RC.ru_mutex); - RC.ru_mask &= ~(1<<ru->idx); - pthread_cond_signal(&RC.ru_cond); - pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); // Start RF device if any @@ -745,41 +766,7 @@ int stop_rf(RU_t *ru) { return 0; } -void init_precoding_weights(PHY_VARS_eNB *eNB) { - int layer,ru_id,aa,re,ue,tb; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - RU_t *ru; - LTE_eNB_DLSCH_t *dlsch; - - // init precoding weigths - for (ue=0; ue<NUMBER_OF_UE_MAX; ue++) { - for (tb=0; tb<2; tb++) { - dlsch = eNB->dlsch[ue][tb]; - - for (layer=0; layer<4; layer++) { - int nb_tx=0; - - for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { - ru = RC.ru[ru_id]; - nb_tx+=ru->nb_tx; - } - - dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *)); - - for (aa=0; aa<nb_tx; aa++) { - dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); - - for (re=0; re<fp->ofdm_symbol_size; re++) { - dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; - } - } - } - } - } -} - void set_function_spec_param(RU_t *ru) { - switch (ru->if_south) { case LOCAL_RF: { // this is an RU with integrated RF (RRU, eNB) ru->do_prach = 0; // no prach processing in RU @@ -819,21 +806,20 @@ void set_function_spec_param(RU_t *ru) { //extern void RCconfig_RU(void); -void init_RU(char *rf_config_file) { +void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t time_source,int send_dmrssync) { int ru_id; RU_t *ru; PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; int i; int CC_id; // create status mask - RC.ru_mask = 0; pthread_mutex_init(&RC.ru_mutex,NULL); pthread_cond_init(&RC.ru_cond,NULL); // read in configuration file) printf("configuring RU from file\n"); RCconfig_RU(); LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n", - RC.nb_L1_inst,RC.nb_RU,get_nprocs()); + RC.nb_L1_inst,RC.nb_RU,get_nprocs()); if (RC.nb_CC != 0) for (i=0; i<RC.nb_L1_inst; i++) @@ -847,16 +833,38 @@ void init_RU(char *rf_config_file) { ru->rf_config_file = rf_config_file; ru->idx = ru_id; ru->ts_offset = 0; + + if (ru->is_slave == 1) { + ru->in_synch = 0; + ru->generate_dmrs_sync = 0; + } else { + ru->in_synch = 1; + ru->generate_dmrs_sync=send_dmrssync; + } + + ru->cmd = EMPTY; + ru->south_out_cnt= 0; // use eNB_list[0] as a reference for RU frame parameters // NOTE: multiple CC_id are not handled here yet! + ru->openair0_cfg.clock_source = clock_source; + ru->openair0_cfg.time_source = time_source; + + // ru->generate_dmrs_sync = (ru->is_slave == 0) ? 1 : 0; + if (ru->generate_dmrs_sync == 1) { + generate_ul_ref_sigs(); + ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms.ofdm_symbol_size*2*sizeof(int16_t)); + } + + ru->wakeup_L1_sleeptime = 2000; + ru->wakeup_L1_sleep_cnt_max = 3; if (ru->num_eNB > 0) { LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", - __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); if (ru->eNB_list[0] == 0) { LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", - __FUNCTION__); + __FUNCTION__); ru->eNB_list[0] = RC.eNB[0][0]; ru->num_eNB=1; // @@ -916,8 +924,6 @@ void RCconfig_RU(void) { if ( RUParamList.numelt > 0) { RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - RC.ru_mask=(1<<RC.nb_RU) - 1; - printf("Set RU mask to %lx\n",RC.ru_mask); for (j = 0; j < RC.nb_RU; j++) { RC.ru[j] = (RU_t *)malloc(sizeof(RU_t)); diff --git a/executables/split_headers.h b/executables/split_headers.h index 1fe4088971cca48c84655da5dc09d9ce2d60a740..3d59f3c199cfe7e5c6e9d76c0f55745e5227ee87 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -23,6 +23,7 @@ typedef struct frequency_s { } frequency_t; int createListner (port); -int receiveSubFrame(int sock, uint64_t expectedTS, void* bufferZone, int bufferSize); -int sendSubFrame(int sock, void* bufferZone, int nbBlocks);} +int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize); +int sendSubFrame(int sock, void *bufferZone, int nbBlocks); +} #endif diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 1bb424d115f59133719c1f65014bb0ea29ee709b..42bf766bafa05006fbd836c749e8ab2547c8e56d 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 @@ -153,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); @@ -319,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++) { @@ -343,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; @@ -425,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; @@ -441,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); } @@ -498,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; } @@ -529,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 diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index dcd79668742a2b71a4a7ccc695afaa35c308855e..37e94de2b6f049c98d11ec51bc224bb6aae85dc7 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -80,7 +80,7 @@ unsigned short config_frames[4] = {2,9,11,13}; //#include "PHY/TOOLS/time_meas.h" #ifndef OPENAIR2 -#include "UTIL/OTG/otg_vars.h" + #include "UTIL/OTG/otg_vars.h" #endif @@ -91,6 +91,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "system.h" + #include "lte-softmodem.h" #include "NB_IoT_interface.h" @@ -107,6 +108,10 @@ pthread_mutex_t sync_mutex; int sync_var=-1; //!< protected by mutex \ref sync_mutex. int config_sync_var=-1; +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + + volatile int oai_exit = 0; uint32_t downlink_frequency[MAX_NUM_CCs][4]; @@ -145,10 +150,18 @@ char ref[128] = "internal"; char channels[128] = "0"; int rx_input_level_dBm; + int otg_enabled; + + uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + + extern void init_eNB_afterRU(void); extern void phy_free_RU(RU_t *); @@ -159,11 +172,73 @@ int numerology = 0; THREAD_STRUCT thread_struct; /* struct for ethernet specific parameters given in eNB conf file */ eth_params_t *eth_params; + double cpuf; +/* forward declarations */ + /* forward declarations */ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + +#if 1 + + if (changed) print_difftimes(); + +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + + void signal_handler(int sig) { void *array[10]; size_t size; @@ -181,6 +256,7 @@ void signal_handler(int sig) { } } + void exit_function(const char *file, const char *function, const int line, const char *s) { int ru_id; @@ -209,6 +285,7 @@ void exit_function(const char *file, const char *function, const int line, const exit(1); } + static void get_options(void) { CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); get_common_options(); @@ -232,6 +309,10 @@ static void get_options(void) { } } + + + + void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { int CC_id; @@ -446,11 +527,14 @@ int main( int argc, char **argv ) { int CC_id = 0; int ru_id; - AssertFatal(load_configmodule(argc,argv,0) != NULL, - "[SOFTMODEM] Error, configuration module init failed\n"); + if ( load_configmodule(argc,argv,0) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + mode = normal_txrx; logInit(); + printf("Reading in command-line options\n"); get_options (); AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n"); @@ -472,14 +556,21 @@ int main( int argc, char **argv ) { EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; + if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { + fprintf(stderr,"Getting configuration failed\n"); + exit(-1); + } + #if T_TRACER T_Config_Init(); #endif //randominit (0); set_taus_seed (0); + printf("configuring for RAU/RRU\n"); - if (opp_enabled ==1) + if (opp_enabled ==1) { reset_opp_meas(); + } itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // allows to forward in wireshark L2 protocol for decoding @@ -491,8 +582,9 @@ int main( int argc, char **argv ) { /* Start the agent. If it is turned off in the configuration, it won't start */ RCconfig_flexran(); - for (i = 0; i < RC.nb_inst; i++) + for (i = 0; i < RC.nb_inst; i++) { flexran_agent_start(i); + } /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ @@ -521,7 +613,7 @@ int main( int argc, char **argv ) { ctxt.subframe = 0; pdcp_run(&ctxt); } - + /* start threads if only L1 or not a CU */ if (RC.nb_inst == 0 || !NODE_IS_CU(RC.rrc[0]->node_type)) { // init UE_PF_PO and mutex lock @@ -531,53 +623,56 @@ int main( int argc, char **argv ) { pthread_mutex_init(&sync_mutex, NULL); rt_sleep_ns(10*100000000ULL); - + if (NFAPI_MODE!=NFAPI_MONOLITHIC) { LOG_I(ENB_APP,"NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); } - + if (NFAPI_MODE==NFAPI_MODE_VNF) {// VNF #if defined(PRE_SCD_THREAD) init_ru_vnf(); // ru pointer is necessary for pre_scd. #endif wait_nfapi_init("main?"); } - + LOG_I(ENB_APP,"START MAIN THREADS\n"); // start the main threads number_of_cards = 1; printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); - + if (RC.nb_L1_inst > 0) { printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); init_eNB(get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); // for (inst=0;inst<RC.nb_L1_inst;inst++) // for (CC_id=0;CC_id<RC.nb_L1_CC[inst];CC_id++) phy_init_lte_eNB(RC.eNB[inst][CC_id],0,0); } - printf("wait_eNBs()\n"); - wait_eNBs(); - printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); - - // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. - // but RU thread deals with pre_scd and this is necessary in VNF and simulator. - // some initialization is necessary and init_ru_vnf do this. - if (RC.nb_RU >0 && NFAPI_MODE!=NFAPI_MODE_VNF) { - printf("Initializing RU threads\n"); + + // no need to wait: openair_rrc_eNB_configuration() is called earlier from this thread + // openair_rrc_eNB_configuration()->init_SI()->rrc_mac_config_req_eNB ()->phy_config_request () sets the wait_eNBs() tested flag + // wait_eNBs(); + // printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + + // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. + // but RU thread deals with pre_scd and this is necessary in VNF and simulator. + // some initialization is necessary and init_ru_vnf do this. + if (RC.nb_RU >0 && NFAPI_MODE!=NFAPI_MODE_VNF) { + printf("Initializing RU threads\n"); init_RU(get_softmodem_params()->rf_config_file,get_softmodem_params()->clock_source,get_softmodem_params()->timing_source,get_softmodem_params()->send_dmrs_sync); - - for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { - RC.ru[ru_id]->rf_map.card=0; - RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + RC.ru[ru_id]->rf_map.card=0; + RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); + } } - + config_sync_var=0; - + if (NFAPI_MODE==NFAPI_MODE_PNF) { // PNF wait_nfapi_init("main?"); } - + printf("wait RUs\n"); // end of CI modifications // fixme: very weird usage of bitmask @@ -604,6 +699,7 @@ int main( int argc, char **argv ) { pthread_mutex_unlock(&sync_mutex); config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); } + // wait for end of program LOG_UI(ENB_APP,"TYPE <CTRL-C> TO TERMINATE\n"); // CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file @@ -648,17 +744,17 @@ int main( int argc, char **argv ) { for(ru_id=0; ru_id<RC.nb_RU; ru_id++) { if (RC.ru[ru_id]->rfdevice.trx_end_func) { - RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); - RC.ru[ru_id]->rfdevice.trx_end_func = NULL; + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_end_func = NULL; } if (RC.ru[ru_id]->ifdevice.trx_end_func) { - RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); - RC.ru[ru_id]->ifdevice.trx_end_func = NULL; + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_end_func = NULL; } } } - + terminate_opt(); logClean(); printf("Bye.\n");