From 286893a1ed6d87ff777ebe00ad868fde4c1480d7 Mon Sep 17 00:00:00 2001 From: Eurecom Date: Mon, 27 Sep 2021 07:21:00 +0200 Subject: [PATCH 001/226] commit before merge --- openair1/PHY/NR_TRANSPORT/nr_dci.c | 4 ++-- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 194c7c0c56..77ad962d56 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -97,8 +97,8 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, cset_start_symb = pdcch_pdu_rel15->StartSymbolIndex; cset_nsymb = pdcch_pdu_rel15->DurationSymbols; dci_idx = 0; - LOG_D(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); - LOG_D(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); + LOG_I(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); + LOG_I(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); // DMRS length is per OFDM symbol uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE) uint32_t encoded_length = dci_pdu->AggregationLevel*108; //2(QPSK)*9(per RB)*6(REG per CCE) diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index e7a3c61c51..67ca6b9169 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -942,7 +942,7 @@ extern "C" { LOG_I(HW, "openair0_cfg[0].sdr_addrs == '%s'\n", openair0_cfg[0].sdr_addrs); LOG_I(HW, "openair0_cfg[0].clock_source == '%d' (internal = %d, external = %d)\n", openair0_cfg[0].clock_source,internal,external); usrp_state_t *s ; - int choffset = 1; + int choffset = 0; if ( device->priv == NULL) { s=(usrp_state_t *)calloc(sizeof(usrp_state_t),1); From d9235268b46e5c7ecedf783c2167b56669b404da Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 29 Sep 2021 21:32:22 +0200 Subject: [PATCH 002/226] MAC statistics in separate thread --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 89 ++-------------------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_gNB/main.c | 81 ++++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 4 files changed, 89 insertions(+), 83 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index e3ee1d9888..f9f8524f7f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -62,87 +62,6 @@ uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; uint8_t vnf_first_sched_entry = 1; -void clear_mac_stats(gNB_MAC_INST *gNB) { - memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t)); -} -#define MACSTATSSTRLEN 16384 -void dump_mac_stats(gNB_MAC_INST *gNB) -{ - NR_UE_info_t *UE_info = &gNB->UE_info; - int num = 1; - FILE *fd=fopen("nrMAC_stats.log","w"); - AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno)); - char output[MACSTATSSTRLEN]; - memset(output,0,MACSTATSSTRLEN); - int stroff=0; - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { - - stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", - UE_id, - UE_info->rnti[UE_id], - num++, - UE_info->num_UEs, - UE_info->UE_sched_ctrl[UE_id].ph, - UE_info->UE_sched_ctrl[UE_id].pcmax); - - LOG_I(NR_MAC, "UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", - UE_id, - UE_info->rnti[UE_id], - num++, - UE_info->num_UEs, - UE_info->UE_sched_ctrl[UE_id].ph, - UE_info->UE_sched_ctrl[UE_id].pcmax); - - NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; - const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; - stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n", - UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, - stats->pucch0_DTX, - avg_rsrp, stats->num_rsrp_meas); - LOG_I(NR_MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d\n", - UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors); - stats->num_rsrp_meas = 0; - stats->cumul_rsrp = 0 ; - stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); - stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n", - UE_id, - stats->ulsch_rounds[0], stats->ulsch_rounds[1], - stats->ulsch_rounds[2], stats->ulsch_rounds[3], - stats->ulsch_DTX, - stats->ulsch_errors); - stroff+=sprintf(output+stroff, - "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", - UE_id, - stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); - LOG_I(NR_MAC, "UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); - LOG_I(NR_MAC, "UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_errors %d\n", - UE_id, - stats->ulsch_rounds[0], stats->ulsch_rounds[1], - stats->ulsch_rounds[2], stats->ulsch_rounds[3], - stats->ulsch_errors); - LOG_I(NR_MAC, - "UE %d: ulsch_total_bytes (scheduled/received): %d / %d\n", - UE_id, - stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); - for (int lc_id = 0; lc_id < 63; lc_id++) { - if (stats->lc_bytes_tx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); - } - if (stats->lc_bytes_rx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); - } - } - } - print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL); - if (stroff>0) fprintf(fd,"%s",output); - fclose(fd); -} void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, @@ -362,6 +281,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP); const int bwp_id = 1; + char stats_output[16384]; gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = gNB->common_channels; @@ -429,8 +349,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } - if ((slot == 0) && (frame & 127) == 0) dump_mac_stats(RC.nrmac[module_idP]); - + if ((slot == 0) && (frame & 127) == 0) { + stats_output[0]='\0'; + dump_mac_stats(RC.nrmac[module_idP],stats_output,16384); + LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output); + } // This schedules MIB schedule_nr_mib(module_idP, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 321476d513..51bbcf1c8a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -442,4 +442,5 @@ bool nr_find_nb_rb(uint16_t Qm, void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP); +void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 117c18ae8d..0497eea7e1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -45,6 +45,85 @@ extern RAN_CONTEXT_t RC; +#define MACSTATSSTRLEN 16384 + +void nrmac_stats_thread(void *arg) { + + gNB_MAC_INST *gNB = (gNB_MAC_INST *)arg; + + char output[MACSTATSSTRLEN]; + memset(output,0,MACSTATSSTRLEN); + FILE *fd=fopen("nrMAC_stats.log","w"); + AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno)); + + while (oai_exit == 0) { + dump_mac_stats(gNB,output,MACSTATSSTRLEN); + fprintf(fd,"%s\n",output); + fflush(fd); + usleep(200000); + fseek(fd,0,SEEK_SET); + } + fclose(fd); +} + +void clear_mac_stats(gNB_MAC_INST *gNB) { + memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t)); +} + +void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen) +{ + NR_UE_info_t *UE_info = &gNB->UE_info; + int num = 1; + + int stroff=0; + if (UE_info->num_UEs == 0) return; + + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + + stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", + UE_id, + UE_info->rnti[UE_id], + num++, + UE_info->num_UEs, + UE_info->UE_sched_ctrl[UE_id].ph, + UE_info->UE_sched_ctrl[UE_id].pcmax); + + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; + stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n", + UE_id, + stats->dlsch_rounds[0], stats->dlsch_rounds[1], + stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, + stats->pucch0_DTX, + avg_rsrp, stats->num_rsrp_meas); + stats->num_rsrp_meas = 0; + stats->cumul_rsrp = 0 ; + stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); + stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n", + UE_id, + stats->ulsch_rounds[0], stats->ulsch_rounds[1], + stats->ulsch_rounds[2], stats->ulsch_rounds[3], + stats->ulsch_DTX, + stats->ulsch_errors); + stroff+=sprintf(output+stroff, + "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", + UE_id, + stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); + for (int lc_id = 0; lc_id < 63; lc_id++) { + if (stats->lc_bytes_tx[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + } + if (stats->lc_bytes_rx[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); + } + } + } + print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL); +} + + void mac_top_init_gNB(void) { module_id_t i; @@ -90,6 +169,7 @@ void mac_top_init_gNB(void) RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(i, 0); RC.nrmac[i]->pre_processor_ul = nr_init_fr1_ulsch_preprocessor(i, 0); } + pthread_create(&RC.nrmac[i]->stats_thread,NULL,nrmac_stats_thread,(void*)RC.nrmac[i]); }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++) @@ -103,6 +183,7 @@ void mac_top_init_gNB(void) rrc_init_nr_global_param(); + } else { RC.nrmac = NULL; } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index c2e2b8d562..1a3b654727 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -665,6 +665,7 @@ typedef struct gNB_MAC_INST_s { NR_TAG_t *tag; /// Pointer to IF module instance for PHY NR_IF_Module_t *if_inst; + pthread_t stats_thread; /// Pusch target SNR int pusch_target_snrx10; /// Pucch target SNR From 33371f226a963e5e391a864f42511f6c191982a8 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 5 Oct 2021 11:37:34 +0200 Subject: [PATCH 003/226] initial changes for n41 support with aw2s RRU --- executables/nr-ru.c | 1 - executables/nr-softmodem.c | 4 +++- openair1/PHY/NR_TRANSPORT/nr_dci.c | 4 ++-- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 2 ++ openair1/PHY/NR_TRANSPORT/nr_prach.c | 21 ++++++++++--------- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- openair1/SCHED_NR/fapi_nr_l1.c | 3 ++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 4 ++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 20 ++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- 12 files changed, 37 insertions(+), 30 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 57ab8494bf..4bcfc04b98 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1401,7 +1401,6 @@ void *ru_thread( void *param ) { // Do PRACH RU processing int prach_id=find_nr_prach_ru(ru,proc->frame_rx,proc->tti_rx,SEARCH_EXIST); uint8_t prachStartSymbol,N_dur; - if (prach_id>=0) { T(T_GNB_PHY_PRACH_INPUT_SIGNAL, T_INT(proc->frame_rx), T_INT(proc->tti_rx), T_INT(0), T_BUFFER(&ru->common.rxdata[0][fp->get_samples_slot_timestamp(proc->tti_rx-1,fp,0)]/*-ru->N_TA_offset*/, fp->get_samples_per_slot(proc->tti_rx,fp)*4*2)); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 1b33667b13..a799a54d57 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -335,13 +335,15 @@ int create_gNB_tasks(uint32_t gnb_nb) { for(int i = GNB_INTERFACE_NAME_FOR_NG_AMF_IDX; i <= GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX; i++) { if( NETParams[i].strptr == NULL) { - LOG_E(NGAP, "No configuration in the file.\n"); + LOG_E(NGAP, "No configuration in the file (%d).\n",i); NGAP_CONF_MODE = 0; } else { LOG_D(NGAP, "Configuration in the file: %s.\n",*NETParams[i].strptr); } } + LOG_E(NGAP,"aprefix %s : %s %s %s %s %d %s %d\n",aprefix,NETParams[0].strptr,NETParams[1].strptr,NETParams[2].strptr,NETParams[3].strptr,NETParams[4].iptr,NETParams[5].strptr,NETParams[6].iptr); + if (AMF_MODE_ENABLED) { if (gnb_nb > 0) { /* diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 194c7c0c56..253635ba65 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -97,8 +97,8 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, cset_start_symb = pdcch_pdu_rel15->StartSymbolIndex; cset_nsymb = pdcch_pdu_rel15->DurationSymbols; dci_idx = 0; - LOG_D(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); - LOG_D(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); + LOG_D(PHY, "pdcch: Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); + LOG_D(PHY, "pdcch: Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); // DMRS length is per OFDM symbol uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE) uint32_t encoded_length = dci_pdu->AggregationLevel*108; //2(QPSK)*9(per RB)*6(REG per CCE) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 5e00a37266..627149ac1f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -146,6 +146,8 @@ uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, uint8_t dmrs_Type = rel15->dmrsConfigType; int nb_re_dmrs; uint16_t n_dmrs; + LOG_D(PHY,"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", + rel15->BWPStart,rel15->BWPSize,rel15->rbStart,rel15->rbSize); if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) { nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 4e2fbd4e71..b12a58526d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -68,7 +68,7 @@ int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { } else if ((type == SEARCH_EXIST) && (gNB->prach_vars.list[i].frame == frame) && - (gNB->prach_vars.list[i].slot == slot)) { + (gNB->prach_vars.list[i].slot == slot)) { return i; } } @@ -107,15 +107,15 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) { for (uint16_t i=0; i %d.%d\n", frame,slot,i, ru->prach_list[i].frame,ru->prach_list[i].slot); - if((type == SEARCH_EXIST_OR_FREE) && - (ru->prach_list[i].frame == -1) && - (ru->prach_list[i].slot == -1)) { - pthread_mutex_unlock(&ru->prach_list_mutex); - return i; - } + if((type == SEARCH_EXIST_OR_FREE) && + (ru->prach_list[i].frame == -1) && + (ru->prach_list[i].slot == -1)) { + pthread_mutex_unlock(&ru->prach_list_mutex); + return i; + } else if ((type == SEARCH_EXIST) && - (ru->prach_list[i].frame == frame) && - (ru->prach_list[i].slot == slot)) { + (ru->prach_list[i].frame == frame) && + (ru->prach_list[i].slot == slot)) { pthread_mutex_unlock(&ru->prach_list_mutex); return i; } @@ -185,7 +185,8 @@ void rx_nr_prach_ru(RU_t *ru, rxsigF = ru->prach_rxsigF[prachOccasion]; - AssertFatal(ru->if_south == LOCAL_RF,"we shouldn't call this if if_south != LOCAL_RF\n"); + AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, + "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); for (int aa=0; aanb_rx; aa++){ if (prach_sequence_length == 0) slot2=(slot/fp->slots_per_subframe)*fp->slots_per_subframe; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 8063fe136f..1fa03842cc 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -426,7 +426,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_confidence_level = no_conf ? 1 : 0; uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); uci_pdu->harq->harq_list[0].harq_value = index&0x01; - if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d with confidence level (0 is good, 1 is bad) %d xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + if (1/*no_conf*/) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d with confidence level (0 is good, 1 is bad) %d xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index b2a802ab08..c9b8defca2 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -253,7 +253,8 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_TTI_PRACH_PDU_TYPE for %d.%d\n", frame, slot, UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); - if (gNB->RU_list[0]->if_south == LOCAL_RF) nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + if (gNB->RU_list[0]->if_south == LOCAL_RF || + gNB->RU_list[0]->if_south == REMOTE_IF5) nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); break; } } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index bc22a3602e..f700b092aa 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -453,7 +453,7 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, int SNRtimes10 = dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot) - dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot); - LOG_D(PHY, "Estimated SNR for PUSCH is = %f dB (ulsch_power %f, noise %f)\n", SNRtimes10/10.0,dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot)/10.0,dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot)/10.0); + LOG_I(PHY, "%d.%d: Estimated SNR for PUSCH is = %f dB (ulsch_power %f, noise %f) delay %d\n", frame, slot_rx, SNRtimes10/10.0,dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot)/10.0,dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot)/10.0,sync_pos); if (SNRtimes10 < -640) cqi=0; else if (SNRtimes10 > 635) cqi=255; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 41591b1169..4ac09bab6a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -318,14 +318,14 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); uint16_t sco = absolute_diff%(12*scs_scaling); - AssertFatal(sco==(scs_scaling * ssb_SubcarrierOffset),"absoluteFrequencySSB has a subcarrier offset of %d while it should be %d\n",sco/scs_scaling,ssb_SubcarrierOffset); + AssertFatal(sco==(scs_scaling * (ssb_SubcarrierOffset>>(cfg->ssb_config.scs_common.value))),"absoluteFrequencySSB has a subcarrier offset of %d while it should be %d\n",sco/scs_scaling,ssb_SubcarrierOffset); cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG; cfg->num_tlv++; - cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset; + cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset>>(cfg->ssb_config.scs_common.value); cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 27037446d2..8367abfd3e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -861,7 +861,7 @@ void nr_get_Msg3alloc(module_id_t module_id, // msg3 is scheduled in mixed slot in the following TDD period - uint16_t msg3_nb_rb = 8 + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT); // sdu has 6 or 8 bytes + uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes int mu = ubwp ? ubwp->bwp_Common->genericParameters.subcarrierSpacing : diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 2f23800af9..cbdc00aa61 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -400,14 +400,14 @@ uint32_t schedule_control_sib1(module_id_t module_id, gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize = rbSize; gNB_mac->sched_ctrlCommon->sched_pdsch.rbStart = 0; - LOG_D(MAC,"mcs = %i\n", gNB_mac->sched_ctrlCommon->sched_pdsch.mcs); - LOG_D(MAC,"startSymbolIndex = %i\n", startSymbolIndex); - LOG_D(MAC,"nrOfSymbols = %i\n", nrOfSymbols); - LOG_D(MAC, "rbSize = %i\n", gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize); - LOG_D(MAC,"TBS = %i\n", TBS); - LOG_D(MAC,"dmrs_length %d\n",dmrs_length); - LOG_D(MAC,"N_PRB_DMRS = %d\n",N_PRB_DMRS); - LOG_D(MAC,"mappingtype = %d\n", mappingtype); + LOG_D(NR_MAC,"mcs = %i\n", gNB_mac->sched_ctrlCommon->sched_pdsch.mcs); + LOG_D(NR_MAC,"startSymbolIndex = %i\n", startSymbolIndex); + LOG_D(NR_MAC,"nrOfSymbols = %i\n", nrOfSymbols); + LOG_D(NR_MAC, "rbSize = %i\n", gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize); + LOG_D(NR_MAC,"TBS = %i\n", TBS); + LOG_D(NR_MAC,"dmrs_length %d\n",dmrs_length); + LOG_D(NR_MAC,"N_PRB_DMRS = %d\n",N_PRB_DMRS); + LOG_D(NR_MAC,"mappingtype = %d\n", mappingtype); // Mark the corresponding RBs as used for (int rb = 0; rb < gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize; rb++) { @@ -486,7 +486,9 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, pdsch_pdu_rel15->StartSymbolIndex = StartSymbolIndex; pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols; pdsch_pdu_rel15->dlDmrsSymbPos = dlDmrsSymbPos; - LOG_D(MAC,"dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->dlDmrsSymbPos); + LOG_D(NR_MAC,"sib1:bwpStart %d, bwpSize %d\n",pdsch_pdu_rel15->BWPStart,pdsch_pdu_rel15->BWPSize); + LOG_D(NR_MAC,"sib1:rbStart %d, rbSize %d\n",pdsch_pdu_rel15->rbStart,pdsch_pdu_rel15->rbSize); + LOG_D(NR_MAC,"sib1:dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->dlDmrsSymbPos); /* Fill PDCCH DL DCI PDU */ nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index ec57befd71..49b1a8ff54 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1044,7 +1044,7 @@ void pf_ul(module_id_t module_id, gNB_MAC_INST *nrmac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; NR_UE_info_t *UE_info = &nrmac->UE_info; - const int min_rb = 40; + const int min_rb = 5; float coeff_ue[MAX_MOBILES_PER_GNB]; // UEs that could be scheduled int ue_array[MAX_MOBILES_PER_GNB]; From 3549168347562664433c2d8aa2ce8bdad50d5a43 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 6 Oct 2021 22:43:06 +0200 Subject: [PATCH 004/226] removal of mean signal level --- executables/nr-ru.c | 6 ++- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 52 +++++++++++++++----- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 57ab8494bf..1d0c3eea29 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1367,7 +1367,10 @@ void *ru_thread( void *param ) { initial_wait=0; opp_enabled = opp_enabled0; } - if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul); + if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul); + + + proc->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; proc->tti_tx = (proc->tti_rx + (fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; @@ -1387,6 +1390,7 @@ void *ru_thread( void *param ) { if (ru->feprx) { ru->feprx(ru,proc->tti_rx); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); + if (initial_wait == 0 && proc->frame_rx == 127 ) {LOG_M("rxdata.m","rxs",ru->common.rxdata[0],fp->samples_per_frame,1,1); LOG_M("rxdataF.m","rxsF",RC.gNB[0]->common_vars.rxdataF[0],fp->symbols_per_slot*fp->ofdm_symbol_size,1,1); exit(-1);} LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx); /* LOG_D(PHY,"Copying rxdataF from RU to gNB\n"); diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index b1608b09ea..6cd7c4029f 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -676,25 +676,53 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp // bring RX data into 12 LSBs for softmodem RX for (int i=0; itype==USRP_X300_DEV) { openair0_cfg[0].rx_gain_calib_table = calib_table_x310; std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; - s->usrp->set_rx_dc_offset(true); + // s->usrp->set_rx_dc_offset(true); } if (device->type==USRP_N300_DEV) { From a0eddabbbd9efca935cf5e0e9316a38aa76fcf23 Mon Sep 17 00:00:00 2001 From: Eurecom Date: Wed, 6 Oct 2021 22:44:22 +0200 Subject: [PATCH 005/226] log reduction --- openair1/PHY/NR_TRANSPORT/nr_dci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 77ad962d56..194c7c0c56 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -97,8 +97,8 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, cset_start_symb = pdcch_pdu_rel15->StartSymbolIndex; cset_nsymb = pdcch_pdu_rel15->DurationSymbols; dci_idx = 0; - LOG_I(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); - LOG_I(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); + LOG_D(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart); + LOG_D(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); // DMRS length is per OFDM symbol uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE) uint32_t encoded_length = dci_pdu->AggregationLevel*108; //2(QPSK)*9(per RB)*6(REG per CCE) From 7d7dd29514c4d5d9c2f5d497ca0b8eedf4641009 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 8 Oct 2021 15:44:57 +0200 Subject: [PATCH 006/226] blacklisting of PRBs in configuration file --- executables/nr-ru.c | 1 - .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 6 +- openair1/PHY/defs_gNB.h | 2 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 11 +++- openair2/GNB_APP/gnb_config.c | 55 ++++++++++++++++++- openair2/GNB_APP/gnb_paramdef.h | 6 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 + targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 33 +---------- 8 files changed, 78 insertions(+), 38 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 1d0c3eea29..195285b187 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1390,7 +1390,6 @@ void *ru_thread( void *param ) { if (ru->feprx) { ru->feprx(ru,proc->tti_rx); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); - if (initial_wait == 0 && proc->frame_rx == 127 ) {LOG_M("rxdata.m","rxs",ru->common.rxdata[0],fp->samples_per_frame,1,1); LOG_M("rxdataF.m","rxsF",RC.gNB[0]->common_vars.rxdataF[0],fp->symbols_per_slot*fp->ofdm_symbol_size,1,1); exit(-1);} LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx); /* LOG_D(PHY,"Copying rxdataF from RU to gNB\n"); diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 020117adba..157c9533d0 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -73,8 +73,9 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { int min_I0=1000,max_I0=0; int amin=0,amax=0; + fprintf(fd,"Blacklisted PRBs %d/%d\n",gNB->num_ulprbbl,gNB->frame_parms.N_RB_UL); for (int i=0; iframe_parms.N_RB_UL; i++) { - if (i==(gNB->frame_parms.N_RB_UL>>1) - 1) i+=2; + if (gNB->ulprbbl[i] > 0) continue; if (gNB->measurements.n0_subband_power_tot_dB[i]measurements.n0_subband_power_tot_dB[i]; amin=i;} @@ -82,7 +83,8 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { } for (int i=0; iframe_parms.N_RB_UL; i++) { - fprintf(fd,"%2d.",gNB->measurements.n0_subband_power_tot_dB[i]-gNB->measurements.n0_subband_power_avg_dB); + if (gNB->ulprbbl[i] ==0) fprintf(fd,"%2d.",gNB->measurements.n0_subband_power_tot_dB[i]-gNB->measurements.n0_subband_power_avg_dB); + else fprintf(fd,"X ."); if (i%25 == 24) fprintf(fd,"\n"); } fprintf(fd,"\n"); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 9a1ba7e780..55a60f7a1b 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -855,6 +855,8 @@ typedef struct PHY_VARS_gNB_s { int pusch_thres; int prach_thres; uint64_t bad_pucch; + int num_ulprbbl; + int ulprbbl[275]; /* time_stats_t phy_proc; */ diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index bc22a3602e..f4a98cef64 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -539,11 +539,18 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { int rb2, rb, nb_rb; + int prbpos=0; if (1/*(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1*/){ nb_rb = 0; for (int symbol=0;symbol<14;symbol++) - for (int m=0;m<9;m++) gNB->rb_mask_ul[symbol][m] = 0; - + for (int m=0;m<9;m++) { + gNB->rb_mask_ul[symbol][m] = 0; + for (int i=0;i<32;i++) { + prbpos = (m*32)+i; + if (prbpos>gNB->frame_parms.N_RB_UL) break; + gNB->rb_mask_ul[symbol][m] |= (gNB->ulprbbl[prbpos]>0 ? 1 : 0)<pucch[i]; if (pucch) { diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 209cdd255d..8d15fc3445 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -549,6 +549,31 @@ void RCconfig_nr_flexran() void RCconfig_NR_L1(void) { int j; + paramdef_t GNBSParams[] = GNBSPARAMS_DESC; + ////////// Identification parameters + paramdef_t GNBParams[] = GNBPARAMS_DESC; + + paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; + + config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); + int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; + AssertFatal (num_gnbs > 0,"Failed to parse config file no gnbs %s \n",GNB_CONFIG_STRING_ACTIVE_GNBS); + + config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); + char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr; + if (ulprbbl) LOG_I(NR_PHY,"PRB blacklist %s\n",ulprbbl); + char *pt = strtok(ulprbbl,","); + int prbbl[275]; + int num_prbbl=0; + memset(prbbl,0,275*sizeof(int)); + + while (pt) { + prbbl[atoi(pt)] = 1; + LOG_I(NR_PHY,"Blacklisting prb %d\n",atoi(pt)); + pt = strtok(NULL,","); + num_prbbl++; + } + paramdef_t L1_Params[] = L1PARAMS_DESC; paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST,NULL,0}; @@ -577,6 +602,9 @@ void RCconfig_NR_L1(void) { RC.gNB[j]->pucch0_thres = *(L1_ParamList.paramarray[j][L1_PUCCH0_DTX_THRESHOLD].uptr); RC.gNB[j]->prach_thres = *(L1_ParamList.paramarray[j][L1_PRACH_DTX_THRESHOLD].uptr); RC.gNB[j]->pusch_thres = *(L1_ParamList.paramarray[j][L1_PUSCH_DTX_THRESHOLD].uptr); + RC.gNB[j]->num_ulprbbl = num_prbbl; + LOG_I(NR_PHY,"Copying %d blacklisted PRB to L1 context\n",num_prbbl); + memcpy(RC.gNB[j]->ulprbbl,prbbl,275*sizeof(int)); if(strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) { //sf_ahead = 2; // Need 4 subframe gap between RX and TX }else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) { @@ -633,9 +661,32 @@ void RCconfig_NR_L1(void) { void RCconfig_nr_macrlc() { int j; + + paramdef_t GNBSParams[] = GNBSPARAMS_DESC; + ////////// Identification parameters + paramdef_t GNBParams[] = GNBPARAMS_DESC; + + paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; + + config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); + int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; + AssertFatal (num_gnbs > 0,"Failed to parse config file no gnbs %s \n",GNB_CONFIG_STRING_ACTIVE_GNBS); + + config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); + char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr; + char *pt = strtok(ulprbbl,","); + int prbbl[275]; + int num_prbbl=0; + int prb; + memset(prbbl,0,275*sizeof(int)); + while (pt) { + prb=atoi(pt); + prbbl[prb] = 1; + pt = strtok(NULL,","); + num_prbbl++; + } paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC; paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0}; - config_getlist( &MacRLC_ParamList,MacRLC_Params,sizeof(MacRLC_Params)/sizeof(paramdef_t), NULL); if ( MacRLC_ParamList.numelt > 0) { @@ -702,6 +753,8 @@ void RCconfig_nr_macrlc() { AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } RC.nrmac[j]->ulsch_max_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_INACTIVITY].uptr); + RC.nrmac[j]->num_ulprbbl = num_prbbl; + memcpy(RC.nrmac[j]->ulprbbl,prbbl,num_prbbl*sizeof(prbbl[0])); }// for (j=0;j 0 LOG_E(PHY,"No %s configuration found\n", CONFIG_STRING_MACRLC_LIST); diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 380c6890a5..4618c009b4 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -120,7 +120,7 @@ typedef enum { #define GNB_CONFIG_STRING_DOCSIRS "do_CSIRS" #define GNB_CONFIG_STRING_NRCELLID "nr_cellid" #define GNB_CONFIG_STRING_MINRXTXTIMEPDSCH "min_rxtxtime_pdsch" - +#define GNB_CONFIG_STRING_ULPRBBLACKLIST "ul_prbblacklist" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -146,7 +146,8 @@ typedef enum { {GNB_CONFIG_STRING_SIB1TDA, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_DOCSIRS, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ -{GNB_CONFIG_STRING_MINRXTXTIMEPDSCH, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0} \ +{GNB_CONFIG_STRING_MINRXTXTIMEPDSCH, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0} \ } #define GNB_GNB_ID_IDX 0 @@ -170,6 +171,7 @@ typedef enum { #define GNB_DO_CSIRS_IDX 18 #define GNB_NRCELLID_IDX 19 #define GNB_MINRXTXTIMEPDSCH_IDX 20 +#define GNB_ULPRBBLACKLIST_IDX 21 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define GNBPARAMS_CHECK { \ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 1a3b654727..4adbb70daf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -683,6 +683,8 @@ typedef struct gNB_MAC_INST_s { /// current PDU index (BCH,DLSCH) uint16_t pdu_index[NFAPI_CC_MAX]; + int num_ulprbbl; + int ulprbbl[275]; /// NFAPI Config Request Structure nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 6cd7c4029f..7bccf66c5c 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -679,44 +679,17 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp #if defined(__x86_64__) || defined(__i386__) #ifdef __AVX2__ - __m256i mean=_mm256_setzero_si256(); - int16_t mean16[2]; - for (int j=0; j Date: Fri, 8 Oct 2021 21:21:28 +0200 Subject: [PATCH 007/226] MAC support for prb blacklisting --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 157c9533d0..73b8660e83 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -84,7 +84,7 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { for (int i=0; iframe_parms.N_RB_UL; i++) { if (gNB->ulprbbl[i] ==0) fprintf(fd,"%2d.",gNB->measurements.n0_subband_power_tot_dB[i]-gNB->measurements.n0_subband_power_avg_dB); - else fprintf(fd,"X ."); + else fprintf(fd," X."); if (i%25 == 24) fprintf(fd,"\n"); } fprintf(fd,"\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index ec57befd71..03c0bbe777 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1322,6 +1322,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t int st = 0, e = 0, len = 0; for (int i = 0; i < bwpSize; i++) { + if (RC.nrmac[module_id]->ulprbbl[i] == 1) vrb_map_UL[i]=1; while ((vrb_map_UL[i] & symb) != 0 && i < bwpSize) i++; st = i; From 85d54ac9df34516244b5d7cb8d7f9886dbf09554 Mon Sep 17 00:00:00 2001 From: Eurecom Date: Thu, 14 Oct 2021 15:46:50 +0200 Subject: [PATCH 008/226] logging --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair2/GNB_APP/gnb_config.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 59 ++++++++++--------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index d1fe5ea049..7f5736a33a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -275,7 +275,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); //dumpsig=1; } else { - LOG_D(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, TBS %d) r %d\n", + LOG_I(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, TBS %d) r %d\n", gNB->Mod_id, ulsch_harq->frame, ulsch_harq->slot, rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status, ulsch_harq->round, ulsch_harq->ulsch_pdu.pusch_data.rv_index,ulsch_harq->TBS,r); ulsch_harq->round++; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 8d15fc3445..421f7e17dd 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -754,7 +754,7 @@ void RCconfig_nr_macrlc() { } RC.nrmac[j]->ulsch_max_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_INACTIVITY].uptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; - memcpy(RC.nrmac[j]->ulprbbl,prbbl,num_prbbl*sizeof(prbbl[0])); + memcpy(RC.nrmac[j]->ulprbbl,prbbl,275*sizeof(prbbl[0])); }// for (j=0;j 0 LOG_E(PHY,"No %s configuration found\n", CONFIG_STRING_MACRLC_LIST); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 23b3bf1ddf..ddd7e0334a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1245,6 +1245,7 @@ void pf_ul(module_id_t module_id, const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0); uint16_t rbSize = 0; uint32_t TBS = 0; + nr_find_nb_rb(sched_pusch->Qm, sched_pusch->R, ps->nrOfSymbols, @@ -1255,8 +1256,8 @@ void pf_ul(module_id_t module_id, &rbSize); sched_pusch->rbSize = rbSize; sched_pusch->tb_size = TBS; - LOG_D(NR_MAC,"rbSize %d, TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", - rbSize, sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,sched_ctrl->cce_index,ps->num_dmrs_symb,ps->N_PRB_DMRS); + LOG_I(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", + rbSize, max_rbSize,sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,sched_ctrl->cce_index,ps->num_dmrs_symb,ps->N_PRB_DMRS); /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; @@ -1329,8 +1330,10 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const uint16_t symb = ((1 << nrOfSymbols) - 1) << startSymbolIndex; int st = 0, e = 0, len = 0; + + for (int i = 0; i < bwpSize; i++) + if (RC.nrmac[module_id]->ulprbbl[i] == 1) vrb_map_UL[i]=symb; for (int i = 0; i < bwpSize; i++) { - if (RC.nrmac[module_id]->ulprbbl[i] == 1) vrb_map_UL[i]=1; while ((vrb_map_UL[i] & symb) != 0 && i < bwpSize) i++; st = i; @@ -1348,7 +1351,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */ for (int i = 0; i < bwpSize; i++) rballoc_mask[i] = i >= st && i <= e; - + LOG_D(NR_MAC,"%d.%d : UL start %d, end %d\n",frame,slot,st,e); /* proportional fair scheduling algorithm */ pf_ul(module_id, frame, @@ -1490,30 +1493,30 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size; sched_ctrl->last_ul_frame = sched_pusch->frame; sched_ctrl->last_ul_slot = sched_pusch->slot; - - LOG_D(NR_MAC, - "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", - frame, - slot, - rnti, - sched_pusch->frame, - sched_pusch->slot, - sched_ctrl->aggregation_level, - sched_pusch->rbStart, - sched_pusch->rbSize, - ps->startSymbolIndex, - ps->nrOfSymbols, - ps->ul_dmrs_symb_pos, - sched_pusch->mcs, - sched_pusch->tb_size, - harq_id, - cur_harq->round, - nr_rv_round_map[cur_harq->round], - cur_harq->ndi, - sched_ctrl->estimated_ul_buffer, - sched_ctrl->sched_ul_bytes, - sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, - sched_ctrl->tpc0); + if (sched_pusch->rbSize > 5) + LOG_D(NR_MAC, + "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", + frame, + slot, + rnti, + sched_pusch->frame, + sched_pusch->slot, + sched_ctrl->aggregation_level, + sched_pusch->rbStart, + sched_pusch->rbSize, + ps->startSymbolIndex, + ps->nrOfSymbols, + ps->ul_dmrs_symb_pos, + sched_pusch->mcs, + sched_pusch->tb_size, + harq_id, + cur_harq->round, + nr_rv_round_map[cur_harq->round], + cur_harq->ndi, + sched_ctrl->estimated_ul_buffer, + sched_ctrl->sched_ul_bytes, + sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, + sched_ctrl->tpc0); /* PUSCH in a later slot, but corresponding DCI now! */ From e1eebbad19112008bbbe797b539b920b4c2153c1 Mon Sep 17 00:00:00 2001 From: Eurecom Date: Sat, 16 Oct 2021 11:11:05 +0200 Subject: [PATCH 009/226] CSI RSRP reporting ok. --- openair2/LAYER2/NR_MAC_gNB/config.c | 7 +++++ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 7 ++++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 29 ++++++++++++++----- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index a2c130078e..15dd5c1561 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -626,6 +626,13 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, UE_info->UE_sched_ctrl[UE_id].search_space = get_searchspace(scc, bwpd, target_ss); UE_info->UE_sched_ctrl[UE_id].coreset = get_coreset(Mod_idP, scc, bwpd, UE_info->UE_sched_ctrl[UE_id].search_space, target_ss); UE_info->UE_sched_ctrl[UE_id].maxL = 2; + if (CellGroup->spCellConfig && + CellGroup->spCellConfig->spCellConfigDedicated && + CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && + CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup + ) + compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, Mod_idP); + } } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c1b1ef9762..3fb98620de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1935,7 +1935,12 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG add_nr_list(&UE_info->list, UE_id); memset(&UE_info->mac_stats[UE_id], 0, sizeof(NR_mac_stats_t)); set_Y(UE_info->Y[UE_id], rntiP); - if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) + if (CellGroup && + CellGroup->spCellConfig && + CellGroup->spCellConfig->spCellConfigDedicated && + CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && + CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup + ) compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, mod_idP); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 820aa8ae6a..65972017da 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -362,6 +362,7 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_in struct NR_CSI_ResourceConfig *csi_resourceconfig; // for each CSI measurement report configuration (list of CSI-ReportConfig) + LOG_I(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; // MAC structure for CSI measurement reports (per UE and per report) @@ -416,7 +417,7 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_in } else AssertFatal(1==0,"Only periodic resource configuration currently supported\n"); } - + LOG_I(NR_MAC,"nb_resources %d\n",nb_resources); // computation of bit length depending on the report type switch(reportQuantity_type){ case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): @@ -504,7 +505,7 @@ void nr_csi_meas_reporting(int Mod_idP, // preparation is done in first slot of tdd period if (frame % (period / n_slots_frame) != offset / n_slots_frame) continue; - LOG_D(NR_MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); + LOG_I(NR_MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; const NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 @@ -530,7 +531,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); - + LOG_I(NR_MAC,"Programmed CSI pucch for %d.%d, resource %d, csi_bits %d\n",frame,sched_slot,res_index,curr_pucch->csi_bits); // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; @@ -695,18 +696,27 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { int ssb_index[MAX_NUM_SSB] = {0}; int ssb_rsrp[MAX_NUM_SSB] = {0}; uint8_t idx = 0; - int bwp_id = 1; NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + int bwp_id = sched_ctrl->active_bwp ? 1 : 0; NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; - NR_BWP_Downlink_t *bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; + NR_BWP_Downlink_t *bwp = bwp_id>0 ? + sched_ctrl->active_bwp: + NULL; + + //bwp indicator - int n_dl_bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; + int n_dl_bwp=0; + if (CellGroup->spCellConfig->spCellConfigDedicated && + CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) + n_dl_bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; + uint8_t nr_ssbri_cri = 0; uint8_t nb_of_csi_ssb_report = UE_info->csi_report_template[UE_id][cqi_idx].nb_of_csi_ssb_report; int better_rsrp_reported = -140-(-0); /*minimum_measured_RSRP_value - minimum_differntail_RSRP_value*///considering the minimum RSRP value as better RSRP initially uint8_t diff_rsrp_idx = 0; uint8_t i, j; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; if (n_dl_bwp < 4) @@ -831,7 +841,10 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { } } - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI; + sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = bwp ? + bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI : + CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[0]->tci_PresentInDCI; + //filling pdsch tci state activation deactivation mac ce structure fields if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI) { From 4496b05423f5cff4080895adec85a1346da75cf8 Mon Sep 17 00:00:00 2001 From: Eurecom Date: Sun, 17 Oct 2021 18:03:55 +0200 Subject: [PATCH 010/226] testing CSI reporting and MIMO DL --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 10 +++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 20 +++++++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/main.c | 6 ++++++ openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 - openair2/RRC/NR/rrc_gNB_reconfig.c | 3 ++- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 594557afb1..53116671b9 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -1519,7 +1519,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, #ifdef DEBUG_NR_PUCCH_RX printf("cw_ML %d, metric %d dB\n",cw_ML,corr_dB); #endif - LOG_I(PHY,"slot %d PUCCH2 cw_ML %d, metric %d dB\n",slot,cw_ML,corr_dB); + LOG_D(PHY,"slot %d PUCCH2 cw_ML %d, metric %d dB\n",slot,cw_ML,corr_dB); decodedPayload[0]=(uint64_t)cw_ML; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 9bdedb0357..6d7b3fd81f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -905,7 +905,7 @@ void nr_schedule_ue_spec(module_id_t module_id, harq->is_waiting = true; UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "%4d.%2d [DLSCH/PDSCH/PUCCH] UE %d RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d nrOfLayer %d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) TPC %d\n", frame, slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index ea1eae17e2..57500ee56d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -418,7 +418,7 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, NR_PDSCH_Config_t *pdsch_Config=NULL; if (bwpd) pdsch_Config = bwpd->pdsch_Config->choice.setup; - LOG_I(NR_MAC,"tda %d, ps->time_domain_allocation %d,layers %d, ps->nrOfLayers %d, pdsch_config %p\n",tda,ps->time_domain_allocation,layers,ps->nrOfLayers,pdsch_Config); + LOG_D(NR_MAC,"tda %d, ps->time_domain_allocation %d,layers %d, ps->nrOfLayers %d, pdsch_config %p\n",tda,ps->time_domain_allocation,layers,ps->nrOfLayers,pdsch_Config); if (ps->time_domain_allocation != tda) { reset_dmrs = true; ps->time_domain_allocation = tda; @@ -440,7 +440,7 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, } const long dci_format = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - LOG_I(NR_MAC,"dci_format %d\n",(int)dci_format); + LOG_D(NR_MAC,"dci_format %d\n",(int)dci_format); if (dci_format == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0 || pdsch_Config == NULL) { if (ps->nrOfSymbols == 2 && ps->mapping_type == NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeB) @@ -456,7 +456,7 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, ps->nrOfLayers = 1; } else { - LOG_I(NR_MAC,"checking layers\n"); + LOG_D(NR_MAC,"checking layers\n"); if (ps->nrOfLayers != layers) { reset_dmrs = true; ps->nrOfLayers = layers; @@ -468,7 +468,7 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, if (reset_dmrs) { ps->dl_dmrs_symb_pos = fill_dmrs_mask(bwpd ? bwpd->pdsch_Config->choice.setup : NULL, scc->dmrs_TypeA_Position, ps->nrOfSymbols, ps->startSymbolIndex, ps->mapping_type, ps->frontloaded_symb); ps->N_DMRS_SLOT = get_num_dmrs(ps->dl_dmrs_symb_pos); - LOG_I(NR_MAC,"bwpd0 %p, bwpd %p : Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",bwpd0,bwpd,ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); + LOG_D(NR_MAC,"bwpd0 %p, bwpd %p : Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",bwpd0,bwpd,ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); } } @@ -2349,7 +2349,7 @@ void nr_csirs_scheduling(int Mod_idP, if((frame*n_slots_frame+slot-offset)%period == 0) { - LOG_I(MAC,"Scheduling CSI-RS in frame %d slot %d\n",frame,slot); + LOG_D(NR_MAC,"Scheduling CSI-RS in frame %d slot %d\n",frame,slot); nfapi_nr_dl_tti_request_pdu_t *dl_tti_csirs_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset((void*)dl_tti_csirs_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index da18f324ef..4b23ab4656 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -60,7 +60,7 @@ void nr_fill_nfapi_pucch(module_id_t mod_id, memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t)); future_ul_tti_req->n_pdus += 1; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "%s %4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, DAI %d, CSI %d on res %d\n", pucch->dai_c>0 ? "pucch_acknak" : "", frame, @@ -78,7 +78,7 @@ void nr_fill_nfapi_pucch(module_id_t mod_id, NR_BWP_UplinkDedicated_t *ubwpd; ubwpd = cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL; - LOG_I(NR_MAC,"pucch_acknak: %d.%d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch in %d.%d\n",frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot); + LOG_D(NR_MAC,"pucch_acknak: %d.%d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch in %d.%d\n",frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot); nr_configure_pucch(pucch_pdu, scc, UE_info->CellGroup[UE_id], @@ -556,7 +556,7 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_in struct NR_CSI_ResourceConfig *csi_resourceconfig; // for each CSI measurement report configuration (list of CSI-ReportConfig) - LOG_I(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); + LOG_D(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; // MAC structure for CSI measurement reports (per UE and per report) @@ -611,7 +611,7 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_in } else AssertFatal(1==0,"Only periodic resource configuration currently supported\n"); } - LOG_I(NR_MAC,"nb_resources %d\n",nb_resources); + LOG_D(NR_MAC,"nb_resources %d\n",nb_resources); // computation of bit length depending on the report type switch(reportQuantity_type){ case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): @@ -724,7 +724,7 @@ void nr_csi_meas_reporting(int Mod_idP, // preparation is done in first slot of tdd period if (frame % (period / n_slots_frame) != offset / n_slots_frame) continue; - LOG_I(NR_MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); + LOG_D(NR_MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; const NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 @@ -750,7 +750,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); - LOG_I(NR_MAC,"Programmed CSI pucch for %d.%d, resource %d, csi_bits %d\n",frame,sched_slot,res_index,curr_pucch->csi_bits); + LOG_D(NR_MAC,"Programmed CSI pucch for %d.%d, resource %d, csi_bits %d\n",frame,sched_slot,res_index,curr_pucch->csi_bits); // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; @@ -1188,7 +1188,7 @@ int evaluate_ri_report(uint8_t *payload, if ((ri_restriction>>i)&0x01) { if(count == ri_index) { sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri = i; - LOG_I(MAC,"CSI Reported Rank %d\n", i+1); + LOG_D(MAC,"CSI Reported Rank %d\n", i+1); return i; } count++; @@ -1218,7 +1218,7 @@ void evaluate_cqi_report(uint8_t *payload, else AssertFatal(1==0,"CQI Table not present in RRC configuration\n"); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb = temp_cqi; - LOG_I(MAC,"Wide-band CQI for the first TB %d\n", temp_cqi); + LOG_D(MAC,"Wide-band CQI for the first TB %d\n", temp_cqi); if (cqi_bitlen > 4) { temp_cqi = pickandreverse_bits(payload, 4, cumul_bits); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_2tb = temp_cqi; @@ -1243,7 +1243,7 @@ uint8_t evaluate_pmi_report(uint8_t *payload, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1 = temp_pmi&((1<CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2 = (temp_pmi>>x1_bitlen)&((1<CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); @@ -1262,7 +1262,7 @@ int evaluate_li_report(uint8_t *payload, if (li_bitlen>0) { int temp_li = pickandreverse_bits(payload, li_bitlen, cumul_bits); - LOG_I(MAC,"LI %d\n",temp_li); + LOG_D(MAC,"LI %d\n",temp_li); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.li = temp_li; } return li_bitlen; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 89410b6c2b..0c9c5bd76e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1261,7 +1261,7 @@ void pf_ul(module_id_t module_id, &rbSize); sched_pusch->rbSize = rbSize; sched_pusch->tb_size = TBS; - LOG_I(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", + LOG_D(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", rbSize, max_rbSize,sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,sched_ctrl->cce_index,ps->num_dmrs_symb,ps->N_PRB_DMRS); /* Mark the corresponding RBs as used */ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 0497eea7e1..7c7c992afc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -96,6 +96,12 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen) stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, stats->pucch0_DTX, avg_rsrp, stats->num_rsrp_meas); + stroff+=sprintf(output+stroff,"UE %d: CQI %d, RI %d, PMI (%d,%d)\n", + UE_id, + UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, + UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.ri+1, + UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, + UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0 ; stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 121696744b..438ba0626a 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1406,7 +1406,6 @@ void fill_initial_SpCellConfig(rnti_t rnti, } csi_MeasConfig->csi_IM_ResourceToReleaseList = NULL; - csi_MeasConfig->csi_IM_ResourceSetToAddModList = NULL; csi_MeasConfig->csi_IM_ResourceSetToReleaseList = NULL; csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList = calloc(1,sizeof(*csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList)); diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index a54ce7856a..1697580640 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -1342,7 +1342,8 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset)); nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; nzpcsi0->periodicityAndOffset->choice.slots320 = 0; - nzpcsi0->qcl_InfoPeriodicCSI_RS = NULL; + nzpcsi0->qcl_InfoPeriodicCSI_RS = calloc(1,sizeof(*nzpcsi0->qcl_InfoPeriodicCSI_RS)); + *nzpcsi0->qcl_InfoPeriodicCSI_RS=0; ASN_SEQUENCE_ADD(&csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list,nzpcsi0); } else From 6d6dd8f1775a097fafe045f6c76d33c6a805273b Mon Sep 17 00:00:00 2001 From: Eurecom Date: Sun, 31 Oct 2021 21:00:50 +0100 Subject: [PATCH 011/226] small modification in UE RX for handling DMRS configuration --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 9029c23664..b3f087ac75 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -267,7 +267,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - ps->nrOfLayers = g_nrOfLayers; + ps->nrOfLayers = 0; int dci_format = sched_ctrl->search_space && sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats ? NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 30ae6b2c97..a82b4f1306 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1015,7 +1015,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr mac->scc? mac->scc->dmrs_TypeA_Position:mac->mib->dmrs_TypeA_Position, dlsch_config_pdu_1_1->number_symbols, dlsch_config_pdu_1_1->start_symbol, - mappingtype); + mappingtype, + dlsch_config_pdu_1_1->n_front_load_symb); dlsch_config_pdu_1_1->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? NFAPI_NR_DMRS_TYPE1 : NFAPI_NR_DMRS_TYPE2; @@ -1095,6 +1096,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr (table_7_3_2_3_3_1[dci->antenna_ports.val][2]<<1) + (table_7_3_2_3_3_1[dci->antenna_ports.val][2]<<2) + (table_7_3_2_3_3_1[dci->antenna_ports.val][4]<<3)); + dlsch_config_pdu_1_1->n_front_load_symb = 1; } if ((dmrs_type == NULL) && (max_length != NULL)){ // Table 7.3.1.2.2-2: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=2 @@ -1181,7 +1183,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr } /* dmrs symbol positions*/ - dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config, + dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_Config, mac->scc->dmrs_TypeA_Position, dlsch_config_pdu_1_1->number_symbols, dlsch_config_pdu_1_1->start_symbol, From a0f654573310255759389b02bb0c69c006761b3f Mon Sep 17 00:00:00 2001 From: Eurecom Date: Sun, 31 Oct 2021 21:14:53 +0100 Subject: [PATCH 012/226] added 133/162 PRBs to nr_dlsim --- openair1/SIMULATION/NR_PHY/dlsim.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index b3f087ac75..cc863e19c6 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -826,6 +826,14 @@ int main(int argc, char **argv) fs = 61.44e6; bw = 40e6; } + else if (mu == 1 && N_RB_DL == 133) { + fs = 61.44e6; + bw = 50e6; + } + else if (mu == 1 && N_RB_DL == 162) { + fs = 61.44e6; + bw = 60e6; + } else if (mu == 3 && N_RB_DL == 66) { fs = 122.88e6; bw = 100e6; From e4a7eda96878e2e43c90926619f3333429cbdc0c Mon Sep 17 00:00:00 2001 From: yihz Date: Tue, 7 Dec 2021 10:43:28 +0800 Subject: [PATCH 013/226] base on 2021.w48, diff_1206_2.diff, UL_NR_MIMO 4*4 --- diff_1206_2.txt | 4257 +++++++++++++++++ executables/nr-softmodem-common.h | 1 + executables/nr-softmodem.h | 2 + executables/nr-ue.c | 5 +- executables/nr-uesoftmodem.c | 7 +- .../nfapi/public_inc/fapi_nr_ue_interface.h | 3 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 3 +- nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 6 +- openair1/PHY/INIT/nr_init.c | 20 +- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair1/PHY/INIT/nr_init_ue.c | 5 +- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 9 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 30 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 32 + openair1/PHY/NR_TRANSPORT/nr_ulsch.h | 6 + .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 1363 +++++- .../NR_TRANSPORT/nr_ulsch_llr_computation.c | 28 +- openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c | 6 +- .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 9 + openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 357 +- openair1/PHY/defs_gNB.h | 6 +- openair1/PHY/defs_nr_UE.h | 3 + openair1/PHY/defs_nr_common.h | 8 +- openair1/SCHED_NR/nr_ru_procedures.c | 3 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 20 +- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 4 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 9 +- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulschsim.c | 32 +- openair1/SIMULATION/NR_PHY/ulsim.c | 271 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 3 + openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 109 +- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 3 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 14 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 28 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 34 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 3 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 + openair2/RRC/NR/nr_rrc_proto.h | 2 + openair2/RRC/NR/rrc_gNB_nsa.c | 4 +- openair2/RRC/NR/rrc_gNB_reconfig.c | 13 +- targets/ARCH/rfsimulator/simulator.c | 17 +- ....sa.band78.fr1.106PRB.usrpb210.4layer.conf | 320 ++ 46 files changed, 6444 insertions(+), 623 deletions(-) create mode 100644 diff_1206_2.txt create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf diff --git a/diff_1206_2.txt b/diff_1206_2.txt new file mode 100644 index 0000000000..ff352f4157 --- /dev/null +++ b/diff_1206_2.txt @@ -0,0 +1,4257 @@ +diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h +index c02155326b..1238b43c27 100644 +--- a/executables/nr-softmodem-common.h ++++ b/executables/nr-softmodem-common.h +@@ -67,6 +67,7 @@ + #define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" + #define CONFIG_HLP_DLMCS_PHYTEST "Set the downlink MCS for PHYTEST mode\n" + #define CONFIG_HLP_DLNL_PHYTEST "Set the downlink nrOfLayers for PHYTEST mode\n" ++#define CONFIG_HLP_ULNL_PHYTEST "Set the uplink nrOfLayers for PHYTEST mode\n" + #define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" + #define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" + #define CONFIG_HLP_ULMCS_PHYTEST "Set the uplink MCS for PHYTEST mode\n" +diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h +index 896c363cbf..a11572c0e1 100644 +--- a/executables/nr-softmodem.h ++++ b/executables/nr-softmodem.h +@@ -23,6 +23,7 @@ + {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ + {"m" , CONFIG_HLP_DLMCS_PHYTEST,0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ + {"l" , CONFIG_HLP_DLNL_PHYTEST,0, uptr:&target_dl_Nl, defintval:0, TYPE_UINT, 0}, \ ++ {"L" , CONFIG_HLP_ULNL_PHYTEST,0, uptr:&target_ul_Nl, defintval:0, TYPE_UINT, 0}, \ + {"t" , CONFIG_HLP_ULMCS_PHYTEST,0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ + {"M" , CONFIG_HLP_DLBW_PHYTEST,0, uptr:&target_dl_bw, defintval:0, TYPE_UINT, 0}, \ + {"T" , CONFIG_HLP_ULBW_PHYTEST,0, uptr:&target_ul_bw, defintval:0, TYPE_UINT, 0}, \ +@@ -36,6 +37,7 @@ + extern threads_t threads; + extern uint32_t target_dl_mcs; + extern uint32_t target_dl_Nl; ++extern uint32_t target_ul_Nl; + extern uint32_t target_ul_mcs; + extern uint32_t target_dl_bw; + extern uint32_t target_ul_bw; +diff --git a/executables/nr-ue.c b/executables/nr-ue.c +index 60ff40abeb..a23f91b1dd 100644 +--- a/executables/nr-ue.c ++++ b/executables/nr-ue.c +@@ -278,7 +278,7 @@ void processSlotTX(void *arg) { + int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx); + uint8_t gNB_id = 0; + +- LOG_D(PHY,"%d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); ++ LOG_D(PHY,"processSlotTX %d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); + if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){ + + // trigger L2 to run ue_scheduler thru IF module +@@ -372,7 +372,8 @@ void processSlotRX(void *arg) { + LOG_D(PHY, "Sending Uplink data \n"); + nr_ue_pusch_common_procedures(UE, + proc->nr_slot_tx, +- &UE->frame_parms,1); ++ &UE->frame_parms, ++ UE->frame_parms.nb_antennas_tx); + } + + if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) { +diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c +index ad5ea982c9..57fd284601 100644 +--- a/executables/nr-uesoftmodem.c ++++ b/executables/nr-uesoftmodem.c +@@ -465,8 +465,11 @@ int main( int argc, char **argv ) { + memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE)); + + set_options(CC_id, UE[CC_id]); +- NR_UE_MAC_INST_t *mac = get_mac_inst(0); +- ++ NR_DL_FRAME_PARMS *fp = &UE[CC_id]->frame_parms; ++ NR_UE_MAC_INST_t *mac = get_mac_inst(0); ++ ++ mac->phy_config.config_req.carrier_config.num_tx_ant = fp->nb_antennas_tx; ++ + if (get_softmodem_params()->sa) { + uint16_t nr_band = get_band(downlink_frequency[CC_id][0],uplink_frequency_offset[CC_id][0]); + mac->nr_band = nr_band; +diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +index 0e923931ad..8b93417cb0 100644 +--- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h ++++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +@@ -298,9 +298,10 @@ typedef struct + uint8_t qam_mod_order; + uint8_t mcs_index; + uint8_t mcs_table; +- uint8_t transform_precoding; ++ uint8_t transformPrecoder; + uint16_t data_scrambling_id; + uint8_t nrOfLayers; ++ uint8_t Tpmi; + //DMRS + uint16_t ul_dmrs_symb_pos; + uint8_t dmrs_config_type; +diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +index 9d245446c8..58ff9037ce 100644 +--- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h ++++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +@@ -1208,9 +1208,10 @@ typedef struct + uint8_t qam_mod_order; + uint8_t mcs_index; + uint8_t mcs_table; +- uint8_t transform_precoding; ++ uint8_t transformPrecoder; + uint16_t data_scrambling_id; + uint8_t nrOfLayers; ++ uint8_t Tpmi; + //DMRS + uint16_t ul_dmrs_symb_pos; + uint8_t dmrs_config_type; +diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +index 7cb74f8562..473b0900bc 100644 +--- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c ++++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +@@ -941,9 +941,10 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui + push8(pusch_pdu->qam_mod_order, ppWritePackedMsg, end) && + push8(pusch_pdu->mcs_index, ppWritePackedMsg, end) && + push8(pusch_pdu->mcs_table, ppWritePackedMsg, end) && +- push8(pusch_pdu->transform_precoding, ppWritePackedMsg, end) && ++ push8(pusch_pdu->transformPrecoder, ppWritePackedMsg, end) && + push16(pusch_pdu->data_scrambling_id, ppWritePackedMsg, end) && + push8(pusch_pdu->nrOfLayers, ppWritePackedMsg, end) && ++ push8(pusch_pdu->Tpmi, ppWritePackedMsg, end) && + push16(pusch_pdu->ul_dmrs_symb_pos, ppWritePackedMsg, end) && + push8(pusch_pdu->dmrs_config_type, ppWritePackedMsg, end) && + push16(pusch_pdu->ul_dmrs_scrambling_id, ppWritePackedMsg, end) && +@@ -4445,9 +4446,10 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(void *tlv, uint8_t **ppReadPacked + pull8(ppReadPackedMsg, &pusch_pdu->qam_mod_order, end) && + pull8(ppReadPackedMsg, &pusch_pdu->mcs_index, end) && + pull8(ppReadPackedMsg, &pusch_pdu->mcs_table, end) && +- pull8(ppReadPackedMsg, &pusch_pdu->transform_precoding, end) && ++ pull8(ppReadPackedMsg, &pusch_pdu->transformPrecoder, end) && + pull16(ppReadPackedMsg, &pusch_pdu->data_scrambling_id, end) && + pull8(ppReadPackedMsg, &pusch_pdu->nrOfLayers, end) && ++ pull8(ppReadPackedMsg, &pusch_pdu->Tpmi, end) && + pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_symb_pos, end) && + pull8(ppReadPackedMsg, &pusch_pdu->dmrs_config_type, end) && + pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_scrambling_id, end) && +diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c +index cd4848ea8c..2ac3230215 100644 +--- a/openair1/PHY/INIT/nr_init.c ++++ b/openair1/PHY/INIT/nr_init.c +@@ -276,11 +276,21 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, + pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_mag = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); +- pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(n_buf*sizeof(int32_t*) ); ++ pusch_vars[ULSCH_id]->rho = (int32_t ***)malloc16_clear(Prx*sizeof(int32_t**) ); ++ pusch_vars[ULSCH_id]->llr_layers = (int16_t **)malloc16(max_ul_mimo_layers*sizeof(int32_t *) ); + + for (i=0; irxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); + pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); ++ pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear( NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); ++ ++ for (int j=0; j< max_ul_mimo_layers; j++) ++ { ++ for (int k=0; krho[i][j*max_ul_mimo_layers+k]=(int32_t *)malloc16_clear( sizeof(int32_t) * fp->N_RB_UL*12*7*2 ); ++ } ++ } + } + for (i=0; iul_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); +@@ -293,8 +303,12 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, + pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); +- pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); +- pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) ); ++ pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); ++ } ++ ++ for (i=0; i< max_ul_mimo_layers; i++) ++ { ++ pusch_vars[ULSCH_id]->llr_layers[i] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear + } + pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear + pusch_vars[ULSCH_id]->ul_valid_re_per_slot = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot); +diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c +index 4024ed1617..169db48e69 100644 +--- a/openair1/PHY/INIT/nr_init_ru.c ++++ b/openair1/PHY/INIT/nr_init_ru.c +@@ -41,7 +41,7 @@ int nr_phy_init_RU(RU_t *ru) { + int p; + int re; + +- LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); ++ LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n",ru_if_types[ru->if_south],ru->nb_tx, ru->nb_rx); + + nfapi_nr_config_request_scf_t *cfg; + ru->nb_log_antennas=0; +diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c +index b60e77e814..11fb6e7d61 100644 +--- a/openair1/PHY/INIT/nr_init_ue.c ++++ b/openair1/PHY/INIT/nr_init_ue.c +@@ -124,7 +124,8 @@ void phy_init_nr_ue_PUSCH(NR_UE_PUSCH *const pusch, + AssertFatal( pusch, "pusch==0" ); + + for (int i=0; itxdataF_layers[i] = (int32_t *)malloc16_clear(NR_MAX_PUSCH_ENCODED_LENGTH*sizeof(int32_t)); ++ pusch->txdataF_layers[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); ++ pusch->txdataF_precoding[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); + } + } + +@@ -143,7 +144,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, + uint16_t N_n_scid[2] = {0,1}; // [HOTFIX] This is a temporary implementation of scramblingID0 and scramblingID1 which are given by DMRS-UplinkConfig + int n_scid; + abstraction_flag = 0; +- LOG_I(PHY, "Initializing UE vars (abstraction %u) for gNB TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); ++ LOG_I(PHY, "Initializing UE vars (abstraction %u) for UE TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); + //LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_gNB_INST); + phy_init_nr_top(ue); + // many memory allocation sizes are hard coded +diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +index 1f164748bf..9a432e8615 100644 +--- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c ++++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +@@ -110,7 +110,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, + fr = filt8_r1; + fmm = filt8_mm1; + fml = filt8_ml1; +- fmr = filt8_m1; ++ fmr = filt8_mm1; + fdcl = filt8_dcl1; + fdcr = filt8_dcr1; + fdclh = filt8_dcl1_h; +@@ -129,9 +129,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, + + //------------------generate DMRS------------------// + +- // transform precoding = 1 means disabled +- if (pusch_pdu->transform_precoding == 1) { +- nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, ++ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { ++ nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], (1000+p), 0, nb_rb_pusch, + (pusch_pdu->bwp_start + pusch_pdu->rb_start)*NR_NB_SC_PER_RB, pusch_pdu->dmrs_config_type); + } + else { // if transform precoding or SC-FDMA is enabled in Uplink +@@ -291,7 +290,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, + printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); + printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); + #endif +- multadd_real_vector_complex_scalar(fml, ++ multadd_real_vector_complex_scalar(fm, + ch, + ul_ch, + 8); +diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +index 4fed3a468f..87e4d57362 100644 +--- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h ++++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +@@ -137,21 +137,22 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + @param nb_rb_pusch The number of RBs allocated (used for Resource Allocation Type 1 in NR) + @param frame_parms, Pointer to frame descriptor structure + */ +-void nr_ulsch_extract_rbs_single(int32_t **rxdataF, +- NR_gNB_PUSCH *pusch_vars, +- int slot, +- unsigned char symbol, +- uint8_t is_dmrs_symbol, +- nfapi_nr_pusch_pdu_t *pusch_pdu, +- NR_DL_FRAME_PARMS *frame_parms); ++void nr_ulsch_extract_rbs(int32_t **rxdataF, ++ NR_gNB_PUSCH *pusch_vars, ++ int slot, ++ unsigned char symbol, ++ uint8_t is_dmrs_symbol, ++ nfapi_nr_pusch_pdu_t *pusch_pdu, ++ NR_DL_FRAME_PARMS *frame_parms); + + void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + NR_gNB_ULSCH_t **ulsch_gNB, +- uint8_t symbol, +- uint8_t start_symbol, +- uint16_t nb_rb, +- pusch_dmrs_type_t pusch_dmrs_type); ++ uint8_t symbol, ++ uint8_t is_dmrs_symbol, ++ uint32_t len, ++ uint8_t nrOfLayers, ++ uint16_t nb_rb); + + /** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal + @param ul_ch_estimates_ext Channel estimates in allocated RBs +@@ -185,9 +186,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + int **ul_ch_mag, + int **ul_ch_magb, + int **rxdataF_comp, +- int **rho, ++ int ***rho, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, ++ int length, + uint8_t is_dmrs_symbol, + unsigned char mod_order, + uint8_t nrOfLayers, +@@ -255,8 +257,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + @param mod_order modulation order + */ + void nr_ulsch_compute_llr(int32_t *rxdataF_comp, +- int32_t **ul_ch_mag, +- int32_t **ul_ch_magb, ++ int32_t *ul_ch_mag, ++ int32_t *ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_rb, + uint32_t nb_re, +diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +index 4278338dbc..3ea19a9970 100644 +--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c ++++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +@@ -137,6 +137,38 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, + #endif + } + ++void nr_ulsch_layer_demapping(int16_t *llr_cw, ++ uint8_t Nl, ++ uint8_t mod_order, ++ uint32_t length, ++ int16_t **llr_layers) ++{ ++ ++ switch (Nl) { ++ ++ case 1: ++ memcpy((void*)llr_cw, (void*)llr_layers[0], (length)*sizeof(int16_t)); ++ break; ++ ++ case 2: ++ case 3: ++ case 4: ++ for (int i=0; i<(length/Nl/mod_order); i++) ++ { ++ for (int l=0; lnumber_of_nr_ulsch_max;i++) { +diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +index 80c10d74b1..0e660351ae 100644 +--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h ++++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +@@ -82,6 +82,12 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, + uint32_t Nid, + uint32_t n_RNTI); + ++void nr_ulsch_layer_demapping(int16_t *llr_cw, ++ uint8_t Nl, ++ uint8_t mod_order, ++ uint32_t length, ++ int16_t **llr_layers); ++ + void nr_ulsch_procedures(PHY_VARS_gNB *gNB, + int frame_rx, + int slot_rx, +diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +index 28dd5ab219..8314c83ad9 100644 +--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c ++++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +@@ -302,26 +302,27 @@ void nr_idft(int32_t *z, uint32_t Msc_PUSCH) + } + + +-void nr_ulsch_extract_rbs_single(int32_t **rxdataF, +- NR_gNB_PUSCH *pusch_vars, +- int slot, +- unsigned char symbol, +- uint8_t is_dmrs_symbol, +- nfapi_nr_pusch_pdu_t *pusch_pdu, +- NR_DL_FRAME_PARMS *frame_parms) ++void nr_ulsch_extract_rbs(int32_t **rxdataF, ++ NR_gNB_PUSCH *pusch_vars, ++ int slot, ++ unsigned char symbol, ++ uint8_t is_dmrs_symbol, ++ nfapi_nr_pusch_pdu_t *pusch_pdu, ++ NR_DL_FRAME_PARMS *frame_parms) + { + + unsigned short start_re, re, nb_re_pusch; +- unsigned char aarx; ++ unsigned char aarx, aatx; + uint32_t rxF_ext_index = 0; + uint32_t ul_ch0_ext_index = 0; + uint32_t ul_ch0_index = 0; +- uint8_t k_prime; +- uint16_t n; ++ //uint8_t k_prime; ++ //uint16_t n; + int16_t *rxF,*rxF_ext; + int *ul_ch0,*ul_ch0_ext; +- uint8_t delta = 0; ++ //uint8_t delta = 0; + int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; ++ + #ifdef DEBUG_RB_EXT + + printf("--------------------symbol = %d-----------------------\n", symbol); +@@ -329,7 +330,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, + + #endif + +- uint8_t is_dmrs_re; ++ uint8_t is_data_re; + start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB)%frame_parms->ofdm_symbol_size; + nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; + #ifdef __AVX2__ +@@ -338,64 +339,95 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, + int nb_re_pusch2 = nb_re_pusch; + #endif + +- for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { ++ for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) ++ { + + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; + rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 +- +- ul_ch0 = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available +- +- ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch2]; +- +- n = 0; +- k_prime = 0; +- rxF_ext_index = 0; +- ul_ch0_ext_index = 0; +- ul_ch0_index = 0; +- +- if (is_dmrs_symbol == 0) { ++ ++ if (is_dmrs_symbol == 0) ++ { + // + //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); +- if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { ++ if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) ++ { + memcpy1((void*)rxF_ext, + (void*)&rxF[start_re*2], + nb_re_pusch*sizeof(int32_t)); +- } else { +- int neg_length = frame_parms->ofdm_symbol_size-start_re; +- int pos_length = nb_re_pusch-neg_length; ++ } ++ else ++ { ++ int neg_length = frame_parms->ofdm_symbol_size-start_re; ++ int pos_length = nb_re_pusch-neg_length; ++ memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); ++ memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); ++ } + +- memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); +- memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); ++ #ifdef SUPPORT_PMI_MATRIC ++ for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) ++ #else ++ aatx = aarx; ++ #endif ++ { ++ ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ++ ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; ++ ++ memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); + } +- memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); + } +- else { +- for (re = 0; re < nb_re_pusch; re++) { +- +- is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type)); +- +-#ifdef DEBUG_RB_EXT +- printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); +-#endif +- +- /* save only data and respective channel estimates */ +- if (is_dmrs_re == 0) { +- rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); +- rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); +- ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; ++ else ++ { ++ #ifdef SUPPORT_PMI_MATRIC ++ for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) ++ #else ++ aatx = aarx; ++ #endif ++ { ++ ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ++ ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; ++ ++ //n = 0; ++ //k_prime = 0; ++ rxF_ext_index = 0; ++ ul_ch0_ext_index = 0; ++ ul_ch0_index = 0; ++ ++ for (re = 0; re < nb_re_pusch; re++) ++ { ++ uint16_t k= start_re+re; ++ ++ is_data_re = allowed_xlsch_re_in_dmrs_symbol(k, start_re, frame_parms->ofdm_symbol_size, pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type); ++ ++ if (++k >= frame_parms->ofdm_symbol_size) ++ { ++ k -= frame_parms->ofdm_symbol_size; ++ } + +-#ifdef DEBUG_RB_EXT +- printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", ++ #ifdef DEBUG_RB_EXT ++ printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); ++ #endif ++ ++ /* save only data and respective channel estimates */ ++ if (is_data_re == 1) ++ { ++ if (aatx == aarx) ++ { ++ rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); ++ rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); ++ rxF_ext_index +=2; ++ } ++ ++ ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; ++ ul_ch0_ext_index++; ++ ++ #ifdef DEBUG_RB_EXT ++ printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", + is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1], + ul_ch0_ext_index, ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0], ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]); +-#endif +- ul_ch0_ext_index++; +- rxF_ext_index +=2; +- } else { +- n += k_prime; +- k_prime ^= 1; ++ #endif ++ } ++ ul_ch0_index++; + } +- ul_ch0_index++; + } + } + } +@@ -406,16 +438,19 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, + NR_gNB_ULSCH_t **ulsch_gNB, + uint8_t symbol, + uint8_t is_dmrs_symbol, +- unsigned short nb_rb, +- pusch_dmrs_type_t pusch_dmrs_type) ++ uint32_t len, ++ uint8_t nrOfLayers, ++ unsigned short nb_rb) + { + + #if defined(__x86_64__)||defined(__i386__) + + short rb, ch_amp; +- unsigned char aarx; ++ unsigned char aarx,aatx; + __m128i *ul_ch128, ch_amp128; + ++ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); ++ + // Determine scaling amplitude based the symbol + + ch_amp = 1024*8; //((pilots) ? (ulsch_gNB[0]->sqrt_rho_b) : (ulsch_gNB[0]->sqrt_rho_a)); +@@ -431,35 +466,26 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, + int off = 0; + #endif + +- for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) { +- +- ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; +- +- if (is_dmrs_symbol==1){ +- if (pusch_dmrs_type == pusch_dmrs_type1) +- nb_rb = nb_rb>>1; +- else +- nb_rb = (2*nb_rb)/3; +- } +- +- for (rb=0;rbnb_antennas_rx; aarx++) ++ { ++ ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; + ++ for (rb=0;rb < nb_rb_0;rb++) ++ { + ul_ch128[0] = _mm_mulhi_epi16(ul_ch128[0], ch_amp128); + ul_ch128[0] = _mm_slli_epi16(ul_ch128[0], 3); + + ul_ch128[1] = _mm_mulhi_epi16(ul_ch128[1], ch_amp128); + ul_ch128[1] = _mm_slli_epi16(ul_ch128[1], 3); + +- if (is_dmrs_symbol) { +- ul_ch128+=2; +- } else { +- ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); +- ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); +- ul_ch128+=3; +- +- } ++ ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); ++ ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); ++ ul_ch128+=3; + } +- } ++ } ++} + #endif + } + +@@ -481,6 +507,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + + int16_t x = factor2(len); + int16_t y = (len)>>x; ++ ++ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); + + #ifdef __AVX2__ + int off = ((nb_rb&1) == 1)? 4:0; +@@ -489,13 +517,16 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + #endif + + for (aatx = 0; aatx < nrOfLayers; aatx++) +- for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { ++ { ++ for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) ++ { + //clear average level + avg128U = _mm_setzero_si128(); + + ul_ch128=(__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; + +- for (rb = 0; rb < len/12; rb++) { ++ for (rb = 0; rb < nb_rb_0; rb++) ++ { + avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x)); + avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[1], ul_ch128[1]), x)); + avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[2], ul_ch128[2]), x)); +@@ -508,7 +539,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + ((int32_t*)&avg128U)[3]) / y; + + } +- ++ } ++ + _mm_empty(); + _m_empty(); + +@@ -520,7 +552,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + int16x4_t *ul_ch128; + + symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; +- ++ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); + for (aatx=0; aatxnb_antennas_rx; aarx++) { + //clear average level +@@ -529,7 +561,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + + ul_ch128 = (int16x4_t *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*frame_parms->N_RB_UL*12]; + +- for (rb = 0; rb < nb_rb; rb++) { ++ for (rb = 0; rb < nb_rb_0; rb++) { + // printf("rb %d : ",rb); + // print_shorts("ch",&ul_ch128[0]); + avg128U = vqaddq_s32(avg128U, vmull_s16(ul_ch128[0], ul_ch128[0])); +@@ -568,14 +600,20 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, + #endif + } + ++ ++ ++//============================================================================================== ++// Pre-processing for LLR computation ++//============================================================================================== + void nr_ulsch_channel_compensation(int **rxdataF_ext, + int **ul_ch_estimates_ext, + int **ul_ch_mag, + int **ul_ch_magb, + int **rxdataF_comp, +- int **rho, ++ int ***rho, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, ++ int length, + uint8_t is_dmrs_symbol, + unsigned char mod_order, + uint8_t nrOfLayers, +@@ -637,20 +675,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128={0},QAM_amp128b={0}; + QAM_amp128b = _mm_setzero_si128(); + +- for (aatx=0; aatxnb_antennas_rx; aarx++) { +- ++ for (aarx=0; aarxnb_antennas_rx; aarx++) ++ { + ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; + ul_ch_mag128 = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; + ul_ch_mag128b = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; +@@ -658,8 +700,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + rxdataF_comp128 = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; + + +- for (rb=0; rb2) { ++ for (rb=0; rb2) ++ { + // get channel amplitude if not QPSK + + //print_shorts("ch:",(int16_t*)&ul_ch128[0]); +@@ -679,6 +723,8 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + ul_ch_mag128[0] = _mm_mulhi_epi16(ul_ch_mag128[0],QAM_amp128); + ul_ch_mag128[0] = _mm_slli_epi16(ul_ch_mag128[0],1); + ++ ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); ++ ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); + // print_ints("ch: = ",(int32_t*)&mmtmpD0); + // print_shorts("QAM_amp:",(int16_t*)&QAM_amp128); + // print_shorts("mag:",(int16_t*)&ul_ch_mag128[0]); +@@ -687,30 +733,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + ul_ch_mag128b[1] = ul_ch_mag128[1]; + ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128); + ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],1); ++ ++ ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128); ++ ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); + +- if (is_dmrs_symbol==0) { +- mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); +- mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); +- mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); +- +- ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); +- ul_ch_mag128b[2] = ul_ch_mag128[2]; ++ mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); ++ mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); ++ mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); + +- ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); +- ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); +- } ++ ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); ++ ul_ch_mag128b[2] = ul_ch_mag128[2]; + +- ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); +- ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); ++ ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); ++ ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); + + +- ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128b); +- ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); ++ ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); ++ ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); + +- if (is_dmrs_symbol==0) { +- ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); +- ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); +- } + } + + // multiply by conjugated channel +@@ -755,117 +795,157 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + // print_shorts("ch:",ul_ch128+1); + // print_shorts("pack:",rxdataF_comp128+1); + +- if (is_dmrs_symbol==0) { +- // multiply by conjugated channel +- mmtmpD0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]); +- // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) +- mmtmpD1 = _mm_shufflelo_epi16(ul_ch128[2],_MM_SHUFFLE(2,3,0,1)); +- mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); +- mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate); +- mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[2]); +- // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit) +- mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); +- mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift); +- mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); +- mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); +- +- rxdataF_comp128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3); +- // print_shorts("rx:",rxdataF128+2); +- // print_shorts("ch:",ul_ch128+2); +- // print_shorts("pack:",rxdataF_comp128+2); +- +- ul_ch128+=3; +- ul_ch_mag128+=3; +- ul_ch_mag128b+=3; +- rxdataF128+=3; +- rxdataF_comp128+=3; +- } else { // we have a smaller PUSCH in symbols with pilots so skip last group of 4 REs and increment less +- ul_ch128+=2; +- ul_ch_mag128+=2; +- ul_ch_mag128b+=2; +- rxdataF128+=2; +- rxdataF_comp128+=2; +- } +- +- } +- } +- } +- +- if (rho) { +- +- for (aarx=0; aarxnb_antennas_rx; aarx++) { +- rho128 = (__m128i *)&rho[aarx][symbol*frame_parms->N_RB_UL*12]; +- ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_UL*12]; +- ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_UL*12]; +- +- for (rb=0; rbnb_antennas_rx][nrOfLayers*nrOfLayers]; ++ int avg_rho_im[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; ++ ++ for (aarx=0; aarxnb_antennas_rx; aarx++) ++ { ++ for (aatx=0; aatx < nrOfLayers; aatx++) ++ { ++ ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ++ ++ for (int atx=0; atx< nrOfLayers; atx++) ++ { ++ avg_rho_re[aarx][aatx*nrOfLayers+atx] = 0; ++ avg_rho_im[aarx][aatx*nrOfLayers+atx] = 0; ++ rho128 = (__m128i *)&rho[aarx][aatx*nrOfLayers+atx][symbol*(off+(nb_rb*12))]; ++ ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[atx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ++ ++ for (rb=0; rbrx_correlation[0][0][aarx] = signal_energy(&rho[aarx][aatx*nb_aatx+atx][symbol*nb_rb*12],rb*12); ++ avg_rho_re[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_re[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); ++ avg_rho_im[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_im[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); ++ //printf("rho[rx]%d tx%d tx%d = Re: %d Im: %d\n",aarx, aatx,atx, avg_rho_re[aarx][aatx*nb_aatx+atx], avg_rho_im[aarx][aatx*nb_aatx+atx]); ++ } ++ } ++ } + } + } + +@@ -1105,19 +1185,23 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, + } + + void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, +- int32_t **rxdataF_comp, +- int32_t **ul_ch_mag, +- int32_t **ul_ch_magb, +- uint8_t symbol, +- uint16_t nb_rb) { ++ int32_t **rxdataF_comp, ++ int32_t **ul_ch_mag, ++ int32_t **ul_ch_magb, ++ int32_t ***rho, ++ uint8_t nrOfLayers, ++ uint8_t symbol, ++ uint16_t nb_rb, ++ int length) { + int n_rx = frame_parms->nb_antennas_rx; + #if defined(__x86_64__) || defined(__i386__) +- __m128i *rxdataF_comp128[1+n_rx],*ul_ch_mag128[1+n_rx],*ul_ch_mag128b[1+n_rx]; ++ __m128i *rxdataF_comp128[2],*ul_ch_mag128[2],*ul_ch_mag128b[2]; + #elif defined(__arm__) + int16x8_t *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b; + int16x8_t *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b; + #endif + int32_t i; ++ uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); + + #ifdef __AVX2__ + int off = ((nb_rb&1) == 1)? 4:0; +@@ -1125,23 +1209,34 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, + int off = 0; + #endif + +- if (frame_parms->nb_antennas_rx>1) { +-#if defined(__x86_64__) || defined(__i386__) +- int nb_re = nb_rb*12; +- for (int aa=0;aanb_antennas_rx;aa++) { +- rxdataF_comp128[aa] = (__m128i *)&rxdataF_comp[aa][(symbol*(nb_re + off))]; +- ul_ch_mag128[aa] = (__m128i *)&ul_ch_mag[aa][(symbol*(nb_re + off))]; +- ul_ch_mag128b[aa] = (__m128i *)&ul_ch_magb[aa][(symbol*(nb_re + off))]; +- } +- for (int aa=1;aanb_antennas_rx;aa++) { +- // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) +- for (i=0; i 1) ++ { ++ #if defined(__x86_64__) || defined(__i386__) ++ for (int aatx=0; aatxnb_antennas_rx][(symbol*(nb_re + off))]; ++ ul_ch_mag128[0] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; ++ ul_ch_mag128b[0] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; ++ ++ for (int aa=1;aa < n_rx;aa++) ++ { ++ rxdataF_comp128[1] = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; ++ ul_ch_mag128[1] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; ++ ul_ch_mag128b[1] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; ++ ++ // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) ++ for (i=0; iN_RB_DL*12]; + rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12]; + ul_ch_mag128_0 = (int16x8_t *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12]; +@@ -1156,7 +1251,7 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, + ul_ch_mag128_0b[i] = vhaddq_s16(ul_ch_mag128_0b[i],ul_ch_mag128_1b[i]); + rxdataF_comp128_0[i] = vqaddq_s16(rxdataF_comp128_0[i],(*(int16x8_t *)&jitterc[0])); + } +-#endif ++ #endif + } + + #if defined(__x86_64__) || defined(__i386__) +@@ -1165,6 +1260,696 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, + #endif + } + ++/* Zero Forcing Rx function: nr_det_HhH() ++ * ++ * ++ * */ ++void nr_ulsch_det_HhH(int32_t *after_mf_00,//a ++ int32_t *after_mf_01,//b ++ int32_t *after_mf_10,//c ++ int32_t *after_mf_11,//d ++ int32_t *det_fin,//1/ad-bc ++ unsigned short nb_rb, ++ unsigned char symbol, ++ int32_t shift) ++{ ++ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; ++ unsigned short rb; ++ __m128i *after_mf_00_128,*after_mf_01_128, *after_mf_10_128, *after_mf_11_128, ad_re_128, bc_re_128; //ad_im_128, bc_im_128; ++ __m128i *det_fin_128, det_re_128; //det_im_128, tmp_det0, tmp_det1; ++ ++ after_mf_00_128 = (__m128i *)after_mf_00; ++ after_mf_01_128 = (__m128i *)after_mf_01; ++ after_mf_10_128 = (__m128i *)after_mf_10; ++ after_mf_11_128 = (__m128i *)after_mf_11; ++ ++ det_fin_128 = (__m128i *)det_fin; ++ ++ for (rb=0; rb<3*nb_rb; rb++) { ++ ++ //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) ++ //The imag part is often zero, we compute only the real part ++ ad_re_128 = _mm_sign_epi16(after_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); ++ ad_re_128 = _mm_madd_epi16(ad_re_128,after_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 ++ //ad_im_128 = _mm_shufflelo_epi16(after_mf_00_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ //ad_im_128 = _mm_shufflehi_epi16(ad_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ //ad_im_128 = _mm_madd_epi16(ad_im_128,after_mf_11_128[0]);//Im: (Q_aI_d + I_aQ_d) ++ ++ //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) ++ //The imag part is often zero, we compute only the real part ++ bc_re_128 = _mm_sign_epi16(after_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); ++ bc_re_128 = _mm_madd_epi16(bc_re_128,after_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 ++ //bc_im_128 = _mm_shufflelo_epi16(after_mf_01_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits ++ //bc_im_128 = _mm_shufflehi_epi16(bc_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits ++ //bc_im_128 = _mm_madd_epi16(bc_im_128,after_mf_10_128[0]);//Im: (Q_bI_c + I_bQ_c) ++ ++ det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); ++ //det_im_128 = _mm_sub_epi32(ad_im_128, bc_im_128); ++ ++ //det in Q30 format ++ det_fin_128[0] = _mm_abs_epi32(det_re_128); ++ ++ ++#ifdef DEBUG_DLSCH_DEMOD ++ printf("\n Computing det_HhH_inv \n"); ++ //print_ints("det_re_128:",(int32_t*)&det_re_128); ++ //print_ints("det_im_128:",(int32_t*)&det_im_128); ++ print_ints("det_fin_128:",(int32_t*)&det_fin_128[0]); ++#endif ++ det_fin_128+=1; ++ after_mf_00_128+=1; ++ after_mf_01_128+=1; ++ after_mf_10_128+=1; ++ after_mf_11_128+=1; ++ } ++ _mm_empty(); ++ _m_empty(); ++} ++ ++/* Zero Forcing Rx function: nr_inv_comp_muli ++ * Complex number multi: z = x*y ++ * = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) ++ * */ ++__m128i nr_ulsch_inv_comp_muli(__m128i input_x, ++ __m128i input_y) ++{ ++ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; ++ ++ __m128i xy_re_128, xy_im_128; ++ __m128i output_z, tmp_z0, tmp_z1; ++ ++ // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) ++ ++ // the real part ++ xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); ++ xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) ++ ++ // the imag part ++ xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) ++ ++ //convert back to Q15 before packing ++ xy_re_128 = _mm_srai_epi32(xy_re_128,4);//(2^15/64*2*16) ++ xy_im_128 = _mm_srai_epi32(xy_im_128,4); ++ ++ tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); ++ //print_ints("unpack lo:",&tmp_z0[0]); ++ tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); ++ //print_ints("unpack hi:",&tmp_z1[0]); ++ output_z = _mm_packs_epi32(tmp_z0,tmp_z1); ++ ++ _mm_empty(); ++ _m_empty(); ++ return(output_z); ++} ++ ++/* Zero Forcing Rx function: nr_conjch0_mult_ch1() ++ * ++ * ++ * */ ++void nr_ulsch_conjch0_mult_ch1(int *ch0, ++ int *ch1, ++ int32_t *ch0conj_ch1, ++ unsigned short nb_rb, ++ unsigned char output_shift0) ++{ ++ //This function is used to compute multiplications in H_hermitian * H matrix ++ short nr_conjugate[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1}; ++ unsigned short rb; ++ __m128i *dl_ch0_128,*dl_ch1_128, *ch0conj_ch1_128, mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; ++ ++ dl_ch0_128 = (__m128i *)ch0; ++ dl_ch1_128 = (__m128i *)ch1; ++ ++ ch0conj_ch1_128 = (__m128i *)ch0conj_ch1; ++ ++ for (rb=0; rb<3*nb_rb; rb++) { ++ ++ mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0],dl_ch1_128[0]); ++ mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[0],_MM_SHUFFLE(2,3,0,1)); ++ mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); ++ mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&nr_conjugate[0]); ++ mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch1_128[0]); ++ mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift0); ++ mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift0); ++ mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); ++ mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); ++ ++ ch0conj_ch1_128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3); ++ ++ /*printf("\n Computing conjugates \n"); ++ print_shorts("ch0:",(int16_t*)&dl_ch0_128[0]); ++ print_shorts("ch1:",(int16_t*)&dl_ch1_128[0]); ++ print_shorts("pack:",(int16_t*)&ch0conj_ch1_128[0]);*/ ++ ++ dl_ch0_128+=1; ++ dl_ch1_128+=1; ++ ch0conj_ch1_128+=1; ++ } ++ _mm_empty(); ++ _m_empty(); ++} ++__m128i nr_ulsch_comp_muli_sum(__m128i input_x, ++ __m128i input_y, ++ __m128i input_w, ++ __m128i input_z, ++ __m128i det) ++{ ++ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; ++ ++ __m128i xy_re_128, xy_im_128, wz_re_128, wz_im_128; ++ __m128i output, tmp_z0, tmp_z1; ++ ++ // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) ++ // the real part ++ xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); ++ xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) ++ ++ // the imag part ++ xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) ++ ++ // complex multiplication (w_re + jw_im)*(z_re + jz_im) = (w_re*z_re - w_im*z_im) + j(w_im*z_re + w_re*z_im) ++ // the real part ++ wz_re_128 = _mm_sign_epi16(input_w,*(__m128i*)&nr_conjug2[0]); ++ wz_re_128 = _mm_madd_epi16(wz_re_128,input_z); //Re: (w_re*z_re - w_im*z_im) ++ ++ // the imag part ++ wz_im_128 = _mm_shufflelo_epi16(input_w,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ wz_im_128 = _mm_shufflehi_epi16(wz_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits ++ wz_im_128 = _mm_madd_epi16(wz_im_128,input_z);//Im: (w_im*z_re + w_re*z_im) ++ ++ ++ xy_re_128 = _mm_sub_epi32(xy_re_128, wz_re_128); ++ xy_im_128 = _mm_sub_epi32(xy_im_128, wz_im_128); ++ //print_ints("rx_re:",(int32_t*)&xy_re_128[0]); ++ //print_ints("rx_Img:",(int32_t*)&xy_im_128[0]); ++ //divide by matrix det and convert back to Q15 before packing ++ int sum_det =0; ++ for (int k=0; k<4;k++) { ++ sum_det += ((((int *)&det[0])[k])>>2); ++ //printf("det_%d = %d log2 =%d \n",k,(((int *)&det[0])[k]),log2_approx(((int *)&det[0])[k])); ++ } ++ ++ xy_re_128 = _mm_slli_epi32(xy_re_128,5); ++ xy_re_128 = _mm_srai_epi32(xy_re_128,log2_approx(sum_det)); ++ xy_re_128 = _mm_slli_epi32(xy_re_128,5); ++ ++ xy_im_128 = _mm_slli_epi32(xy_im_128,5); ++ xy_im_128 = _mm_srai_epi32(xy_im_128,log2_approx(sum_det)); ++ xy_im_128 = _mm_slli_epi32(xy_im_128,5); ++ ++ tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); ++ //print_ints("unpack lo:",&tmp_z0[0]); ++ tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); ++ //print_ints("unpack hi:",&tmp_z1[0]); ++ output = _mm_packs_epi32(tmp_z0,tmp_z1); ++ ++ _mm_empty(); ++ _m_empty(); ++ return(output); ++} ++/* Zero Forcing Rx function: nr_construct_HhH_elements() ++ * ++ * ++ * */ ++void nr_ulsch_construct_HhH_elements(int *conjch00_ch00, ++ int *conjch01_ch01, ++ int *conjch11_ch11, ++ int *conjch10_ch10,// ++ int *conjch20_ch20, ++ int *conjch21_ch21, ++ int *conjch30_ch30, ++ int *conjch31_ch31, ++ int *conjch00_ch01,//00_01 ++ int *conjch01_ch00,//01_00 ++ int *conjch10_ch11,//10_11 ++ int *conjch11_ch10,//11_10 ++ int *conjch20_ch21, ++ int *conjch21_ch20, ++ int *conjch30_ch31, ++ int *conjch31_ch30, ++ int32_t *after_mf_00, ++ int32_t *after_mf_01, ++ int32_t *after_mf_10, ++ int32_t *after_mf_11, ++ unsigned short nb_rb, ++ unsigned char symbol) ++{ ++ //This function is used to construct the (H_hermitian * H matrix) matrix elements ++ unsigned short rb; ++ __m128i *conjch00_ch00_128, *conjch01_ch01_128, *conjch11_ch11_128, *conjch10_ch10_128; ++ __m128i *conjch20_ch20_128, *conjch21_ch21_128, *conjch30_ch30_128, *conjch31_ch31_128; ++ __m128i *conjch00_ch01_128, *conjch01_ch00_128, *conjch10_ch11_128, *conjch11_ch10_128; ++ __m128i *conjch20_ch21_128, *conjch21_ch20_128, *conjch30_ch31_128, *conjch31_ch30_128; ++ __m128i *after_mf_00_128, *after_mf_01_128, *after_mf_10_128, *after_mf_11_128; ++ ++ conjch00_ch00_128 = (__m128i *)conjch00_ch00; ++ conjch01_ch01_128 = (__m128i *)conjch01_ch01; ++ conjch11_ch11_128 = (__m128i *)conjch11_ch11; ++ conjch10_ch10_128 = (__m128i *)conjch10_ch10; ++ ++ conjch20_ch20_128 = (__m128i *)conjch20_ch20; ++ conjch21_ch21_128 = (__m128i *)conjch21_ch21; ++ conjch30_ch30_128 = (__m128i *)conjch30_ch30; ++ conjch31_ch31_128 = (__m128i *)conjch31_ch31; ++ ++ conjch00_ch01_128 = (__m128i *)conjch00_ch01; ++ conjch01_ch00_128 = (__m128i *)conjch01_ch00; ++ conjch10_ch11_128 = (__m128i *)conjch10_ch11; ++ conjch11_ch10_128 = (__m128i *)conjch11_ch10; ++ ++ conjch20_ch21_128 = (__m128i *)conjch20_ch21; ++ conjch21_ch20_128 = (__m128i *)conjch21_ch20; ++ conjch30_ch31_128 = (__m128i *)conjch30_ch31; ++ conjch31_ch30_128 = (__m128i *)conjch31_ch30; ++ ++ after_mf_00_128 = (__m128i *)after_mf_00; ++ after_mf_01_128 = (__m128i *)after_mf_01; ++ after_mf_10_128 = (__m128i *)after_mf_10; ++ after_mf_11_128 = (__m128i *)after_mf_11; ++ ++ for (rb=0; rb<3*nb_rb; rb++) { ++ ++ after_mf_00_128[0] =_mm_adds_epi16(conjch00_ch00_128[0],conjch10_ch10_128[0]);//00_00 + 10_10 ++ if (conjch20_ch20 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch20_ch20_128[0]); ++ if (conjch30_ch30 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch30_ch30_128[0]); ++ ++ after_mf_11_128[0] =_mm_adds_epi16(conjch01_ch01_128[0], conjch11_ch11_128[0]); //01_01 + 11_11 ++ if (conjch21_ch21 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch21_ch21_128[0]); ++ if (conjch31_ch31 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch31_ch31_128[0]); ++ ++ after_mf_01_128[0] =_mm_adds_epi16(conjch00_ch01_128[0], conjch10_ch11_128[0]);//00_01 + 10_11 ++ if (conjch20_ch21 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch20_ch21_128[0]); ++ if (conjch30_ch31 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch30_ch31_128[0]); ++ ++ after_mf_10_128[0] =_mm_adds_epi16(conjch01_ch00_128[0], conjch11_ch10_128[0]);//01_00 + 11_10 ++ if (conjch21_ch20 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch21_ch20_128[0]); ++ if (conjch31_ch30 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch31_ch30_128[0]); ++ ++#ifdef DEBUG_DLSCH_DEMOD ++ if ((rb<=30)) ++ { ++ printf(" \n construct_HhH_elements \n"); ++ print_shorts("after_mf_00_128:",(int16_t*)&after_mf_00_128[0]); ++ print_shorts("after_mf_01_128:",(int16_t*)&after_mf_01_128[0]); ++ print_shorts("after_mf_10_128:",(int16_t*)&after_mf_10_128[0]); ++ print_shorts("after_mf_11_128:",(int16_t*)&after_mf_11_128[0]); ++ } ++#endif ++ conjch00_ch00_128+=1; ++ conjch10_ch10_128+=1; ++ conjch01_ch01_128+=1; ++ conjch11_ch11_128+=1; ++ ++ if (conjch20_ch20 != NULL) conjch20_ch20_128+=1; ++ if (conjch21_ch21 != NULL) conjch21_ch21_128+=1; ++ if (conjch30_ch30 != NULL) conjch30_ch30_128+=1; ++ if (conjch31_ch31 != NULL) conjch31_ch31_128+=1; ++ ++ conjch00_ch01_128+=1; ++ conjch01_ch00_128+=1; ++ conjch10_ch11_128+=1; ++ conjch11_ch10_128+=1; ++ ++ if (conjch20_ch21 != NULL) conjch20_ch21_128+=1; ++ if (conjch21_ch20 != NULL) conjch21_ch20_128+=1; ++ if (conjch30_ch31 != NULL) conjch30_ch31_128+=1; ++ if (conjch31_ch30 != NULL) conjch31_ch30_128+=1; ++ ++ after_mf_00_128 += 1; ++ after_mf_01_128 += 1; ++ after_mf_10_128 += 1; ++ after_mf_11_128 += 1; ++ } ++ _mm_empty(); ++ _m_empty(); ++} ++ ++/* Zero Forcing Rx function: nr_ulsch_zero_forcing_rx_2layers() ++ * ++ * ++ * */ ++uint8_t nr_ulsch_zero_forcing_rx_2layers(int **rxdataF_comp, ++ int **ul_ch_mag, ++ int **ul_ch_magb, ++ int **ul_ch_estimates_ext, ++ unsigned short nb_rb, ++ unsigned char n_rx, ++ unsigned char mod_order, ++ int shift, ++ unsigned char symbol, ++ int length) ++{ ++ int *ch00, *ch01, *ch10, *ch11; ++ int *ch20, *ch30, *ch21, *ch31; ++ uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); ++ ++ #ifdef __AVX2__ ++ int off = ((nb_rb&1) == 1)? 4:0; ++ #else ++ int off = 0; ++ #endif ++ ++ /* we need at least alignment to 16 bytes, let's put 32 to be sure ++ * (maybe not necessary but doesn't hurt) ++ */ ++ int32_t conjch00_ch01[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch01_ch00[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch10_ch11[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch11_ch10[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch00_ch00[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch01_ch01[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch10_ch10[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch11_ch11[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch20_ch20[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch21_ch21[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch30_ch30[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch31_ch31[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch20_ch21[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch30_ch31[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch21_ch20[12*nb_rb] __attribute__((aligned(32))); ++ int32_t conjch31_ch30[12*nb_rb] __attribute__((aligned(32))); ++ ++ int32_t af_mf_00[12*nb_rb] __attribute__((aligned(32))); ++ int32_t af_mf_01[12*nb_rb] __attribute__((aligned(32))); ++ int32_t af_mf_10[12*nb_rb] __attribute__((aligned(32))); ++ int32_t af_mf_11[12*nb_rb] __attribute__((aligned(32))); ++ int32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); ++ ++ switch (n_rx) { ++ case 2:// ++ ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; ++ ch01 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; ++ ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; ++ ch11 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; ++ ch20 = NULL; ++ ch21 = NULL; ++ ch30 = NULL; ++ ch31 = NULL; ++ break; ++ ++ case 4:// ++ ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; ++ ch01 = (int *)&ul_ch_estimates_ext[4][symbol*(off+nb_rb*12)]; ++ ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; ++ ch11 = (int *)&ul_ch_estimates_ext[5][symbol*(off+nb_rb*12)]; ++ ch20 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; ++ ch21 = (int *)&ul_ch_estimates_ext[6][symbol*(off+nb_rb*12)]; ++ ch30 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; ++ ch31 = (int *)&ul_ch_estimates_ext[7][symbol*(off+nb_rb*12)]; ++ break; ++ ++ default: ++ return -1; ++ break; ++ } ++ ++ /* 1- Compute the rx channel matrix after compensation: (1/2^log2_max)x(H_herm x H) ++ * for n_rx = 2 ++ * |conj_H_00 conj_H_10| | H_00 H_01| |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| ++ * | | x | | = | | ++ * |conj_H_01 conj_H_11| | H_10 H_11| |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| ++ * ++ */ ++ ++ if (n_rx>=2){ ++ // (1/2^log2_maxh)*conj_H_00xH_00: (1/(64*2))conjH_00*H_00*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch00, ++ ch00, ++ conjch00_ch00, ++ nb_rb_0, ++ shift); ++ // (1/2^log2_maxh)*conj_H_10xH_10: (1/(64*2))conjH_10*H_10*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch10, ++ ch10, ++ conjch10_ch10, ++ nb_rb_0, ++ shift); ++ // conj_H_00xH_01 ++ nr_ulsch_conjch0_mult_ch1(ch00, ++ ch01, ++ conjch00_ch01, ++ nb_rb_0, ++ shift); // this shift is equal to the channel level log2_maxh ++ // conj_H_10xH_11 ++ nr_ulsch_conjch0_mult_ch1(ch10, ++ ch11, ++ conjch10_ch11, ++ nb_rb_0, ++ shift); ++ // conj_H_01xH_01 ++ nr_ulsch_conjch0_mult_ch1(ch01, ++ ch01, ++ conjch01_ch01, ++ nb_rb_0, ++ shift); ++ // conj_H_11xH_11 ++ nr_ulsch_conjch0_mult_ch1(ch11, ++ ch11, ++ conjch11_ch11, ++ nb_rb_0, ++ shift); ++ // conj_H_01xH_00 ++ nr_ulsch_conjch0_mult_ch1(ch01, ++ ch00, ++ conjch01_ch00, ++ nb_rb_0, ++ shift); ++ // conj_H_11xH_10 ++ nr_ulsch_conjch0_mult_ch1(ch11, ++ ch10, ++ conjch11_ch10, ++ nb_rb_0, ++ shift); ++ } ++ if (n_rx==4){ ++ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2*16))conjH_20*H_20*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch20, ++ ch20, ++ conjch20_ch20, ++ nb_rb_0, ++ shift); ++ ++ // (1/2^log2_maxh)*conj_H_30xH_30: (1/(64*2*4))conjH_30*H_30*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch30, ++ ch30, ++ conjch30_ch30, ++ nb_rb_0, ++ shift); ++ ++ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch20, ++ ch21, ++ conjch20_ch21, ++ nb_rb_0, ++ shift); ++ ++ nr_ulsch_conjch0_mult_ch1(ch30, ++ ch31, ++ conjch30_ch31, ++ nb_rb_0, ++ shift); ++ ++ nr_ulsch_conjch0_mult_ch1(ch21, ++ ch21, ++ conjch21_ch21, ++ nb_rb_0, ++ shift); ++ ++ nr_ulsch_conjch0_mult_ch1(ch31, ++ ch31, ++ conjch31_ch31, ++ nb_rb_0, ++ shift); ++ ++ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 ++ nr_ulsch_conjch0_mult_ch1(ch21, ++ ch20, ++ conjch21_ch20, ++ nb_rb_0, ++ shift); ++ ++ nr_ulsch_conjch0_mult_ch1(ch31, ++ ch30, ++ conjch31_ch30, ++ nb_rb_0, ++ shift); ++ ++ nr_ulsch_construct_HhH_elements(conjch00_ch00, ++ conjch01_ch01, ++ conjch11_ch11, ++ conjch10_ch10,// ++ conjch20_ch20, ++ conjch21_ch21, ++ conjch30_ch30, ++ conjch31_ch31, ++ conjch00_ch01, ++ conjch01_ch00, ++ conjch10_ch11, ++ conjch11_ch10,// ++ conjch20_ch21, ++ conjch21_ch20, ++ conjch30_ch31, ++ conjch31_ch30, ++ af_mf_00, ++ af_mf_01, ++ af_mf_10, ++ af_mf_11, ++ nb_rb_0, ++ symbol); ++ } ++ if (n_rx==2){ ++ nr_ulsch_construct_HhH_elements(conjch00_ch00, ++ conjch01_ch01, ++ conjch11_ch11, ++ conjch10_ch10,// ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ conjch00_ch01, ++ conjch01_ch00, ++ conjch10_ch11, ++ conjch11_ch10,// ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ af_mf_00, ++ af_mf_01, ++ af_mf_10, ++ af_mf_11, ++ nb_rb_0, ++ symbol); ++ } ++ //det_HhH = ad -bc ++ nr_ulsch_det_HhH(af_mf_00,//a ++ af_mf_01,//b ++ af_mf_10,//c ++ af_mf_11,//d ++ determ_fin, ++ nb_rb_0, ++ symbol, ++ shift); ++ /* 2- Compute the channel matrix inversion ********************************** ++ * ++ * |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| ++ * A= | | ++ * |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| ++ * ++ * ++ * ++ *inv(A) =(1/det)*[d -b ++ * -c a] ++ * ++ * ++ **************************************************************************/ ++ __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*ul_ch_mag128_0=NULL,*ul_ch_mag128b_0=NULL,*determ_fin_128;//*dl_ch_mag128_1,*dl_ch_mag128b_1,*dl_ch_mag128r_1 ++ __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; ++ __m128i *after_mf_a_128,*after_mf_b_128, *after_mf_c_128, *after_mf_d_128; ++ __m128i QAM_amp128={0},QAM_amp128b={0}; ++ ++ determ_fin_128 = (__m128i *)&determ_fin[0]; ++ ++ rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[0][symbol*(off+nb_rb*12)];//aatx=0 @ aarx =0 ++ rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[n_rx][symbol*(off+nb_rb*12)];//aatx=1 @ aarx =0 ++ ++ after_mf_a_128 = (__m128i *)af_mf_00; ++ after_mf_b_128 = (__m128i *)af_mf_01; ++ after_mf_c_128 = (__m128i *)af_mf_10; ++ after_mf_d_128 = (__m128i *)af_mf_11; ++ ++ if (mod_order>2) { ++ if (mod_order == 4) { ++ QAM_amp128 = _mm_set1_epi16(QAM16_n1); //2/sqrt(10) ++ QAM_amp128b = _mm_setzero_si128(); ++ } else if (mod_order == 6) { ++ QAM_amp128 = _mm_set1_epi16(QAM64_n1); //4/sqrt{42} ++ QAM_amp128b = _mm_set1_epi16(QAM64_n2); //2/sqrt{42} ++ } ++ ul_ch_mag128_0 = (__m128i *)&ul_ch_mag[0][symbol*(off+nb_rb*12)]; ++ ul_ch_mag128b_0 = (__m128i *)&ul_ch_magb[0][symbol*(off+nb_rb*12)]; ++ } ++ ++ for (int rb=0; rb<3*nb_rb_0; rb++) { ++ if (mod_order>2) { ++ int sum_det =0; ++ for (int k=0; k<4;k++) { ++ sum_det += ((((int *)&determ_fin_128[0])[k])>>2); ++ //printf("det_%d = %d\n",k,sum_det); ++ } ++ ++ mmtmpD2 = _mm_slli_epi32(determ_fin_128[0],5); ++ mmtmpD2 = _mm_srai_epi32(mmtmpD2,log2_approx(sum_det)); ++ mmtmpD2 = _mm_slli_epi32(mmtmpD2,5); ++ ++ mmtmpD3 = _mm_unpacklo_epi32(mmtmpD2,mmtmpD2); ++ ++ mmtmpD2 = _mm_unpackhi_epi32(mmtmpD2,mmtmpD2); ++ ++ mmtmpD2 = _mm_packs_epi32(mmtmpD3,mmtmpD2); ++ ++ ul_ch_mag128_0[0] = mmtmpD2; ++ ul_ch_mag128b_0[0] = mmtmpD2; ++ ++ ul_ch_mag128_0[0] = _mm_mulhi_epi16(ul_ch_mag128_0[0],QAM_amp128); ++ ul_ch_mag128_0[0] = _mm_slli_epi16(ul_ch_mag128_0[0],1); ++ ++ ul_ch_mag128b_0[0] = _mm_mulhi_epi16(ul_ch_mag128b_0[0],QAM_amp128b); ++ ul_ch_mag128b_0[0] = _mm_slli_epi16(ul_ch_mag128b_0[0],1); ++ ++ //print_shorts("mag layer 1:",(int16_t*)&dl_ch_mag128_0[0]); ++ //print_shorts("mag layer 2:",(int16_t*)&dl_ch_mag128_1[0]); ++ //print_shorts("magb layer 1:",(int16_t*)&dl_ch_mag128b_0[0]); ++ //print_shorts("magb layer 2:",(int16_t*)&dl_ch_mag128b_1[0]); ++ //print_shorts("magr layer 1:",(int16_t*)&dl_ch_mag128r_0[0]); ++ //print_shorts("magr layer 2:",(int16_t*)&dl_ch_mag128r_1[0]); ++ } ++ // multiply by channel Inv ++ //rxdataF_zf128_0 = rxdataF_comp128_0*d - b*rxdataF_comp128_1 ++ //rxdataF_zf128_1 = rxdataF_comp128_1*a - c*rxdataF_comp128_0 ++ //printf("layer_1 \n"); ++ mmtmpD0 = nr_ulsch_comp_muli_sum(rxdataF_comp128_0[0], ++ after_mf_d_128[0], ++ rxdataF_comp128_1[0], ++ after_mf_b_128[0], ++ determ_fin_128[0]); ++ ++ //printf("layer_2 \n"); ++ mmtmpD1 = nr_ulsch_comp_muli_sum(rxdataF_comp128_1[0], ++ after_mf_a_128[0], ++ rxdataF_comp128_0[0], ++ after_mf_c_128[0], ++ determ_fin_128[0]); ++ ++ rxdataF_comp128_0[0] = mmtmpD0; ++ rxdataF_comp128_1[0] = mmtmpD1; ++#ifdef DEBUG_DLSCH_DEMOD ++ printf("\n Rx signal after ZF l%d rb%d\n",symbol,rb); ++ print_shorts(" Rx layer 1:",(int16_t*)&rxdataF_comp128_0[0]); ++ print_shorts(" Rx layer 2:",(int16_t*)&rxdataF_comp128_1[0]); ++#endif ++ determ_fin_128 += 1; ++ ul_ch_mag128_0 += 1; ++ ul_ch_mag128b_0 += 1; ++ rxdataF_comp128_0 += 1; ++ rxdataF_comp128_1 += 1; ++ after_mf_a_128 += 1; ++ after_mf_b_128 += 1; ++ after_mf_c_128 += 1; ++ after_mf_d_128 += 1; ++ } ++ _mm_empty(); ++ _m_empty(); ++ return(0); ++} ++ ++//============================================================================================== ++ ++/* Main Function */ + int nr_rx_pusch(PHY_VARS_gNB *gNB, + uint8_t ulsch_id, + uint32_t frame, +@@ -1184,21 +1969,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + gNB->pusch_vars[ulsch_id]->cl_done = 0; + + bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start)*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; +- LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); +- LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); +- ++ LOG_I(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); ++ LOG_I(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); ++ LOG_I(PHY,"ulsch RX %x : start_rb %d nb_rb %d mcs %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_ports %d\n", ++ rel15_ul->rnti,rel15_ul->rb_start,rel15_ul->rb_size,rel15_ul->mcs_index, ++ rel15_ul->nrOfLayers,0,rel15_ul->bwp_start,0,rel15_ul->start_symbol_index,rel15_ul->nr_of_symbols, ++ rel15_ul->num_dmrs_cdm_grps_no_data,rel15_ul->ul_dmrs_symb_pos,rel15_ul->dmrs_ports); + //---------------------------------------------------------- + //--------------------- Channel estimation --------------------- + //---------------------------------------------------------- + start_meas(&gNB->ulsch_channel_estimation_stats); +- for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { ++ for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) ++ { + uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; + LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag); +- if (dmrs_symbol_flag == 1) { ++ ++ if (dmrs_symbol_flag == 1) ++ { + if (gNB->pusch_vars[ulsch_id]->dmrs_symbol == INVALID_VALUE) + gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; + + for (int nl=0; nlnrOfLayers; nl++) ++ { ++ + nr_pusch_channel_estimation(gNB, + slot, + get_dmrs_port(nl,rel15_ul->dmrs_ports), +@@ -1206,6 +1999,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + ulsch_id, + bwp_start_subcarrier, + rel15_ul); ++ } + + nr_gnb_measurements(gNB, ulsch_id, harq_pid, symbol,rel15_ul->nrOfLayers); + +@@ -1214,9 +2008,12 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] = 0; + gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] = 0; + } +- gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( +- &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aarx][symbol * frame_parms->ofdm_symbol_size], ++ for (aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) ++ { ++ gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( ++ &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aatx*gNB->frame_parms.nb_antennas_rx+aarx][symbol * frame_parms->ofdm_symbol_size], + rel15_ul->rb_size * 12); ++ } + for (int rb = 0; rb < rel15_ul->rb_size; rb++) { + gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] += + gNB->measurements.n0_subband_power[aarx][rel15_ul->bwp_start + rel15_ul->rb_start + rb] / +@@ -1234,23 +2031,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + #endif + uint32_t rxdataF_ext_offset = 0; + +- for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { ++ for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) ++ { + uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; +- if (dmrs_symbol_flag == 1) { ++ if (dmrs_symbol_flag == 1) ++ { + if ((rel15_ul->ul_dmrs_symb_pos >> ((symbol + 1) % frame_parms->symbols_per_slot)) & 0x01) + AssertFatal(1==0,"Double DMRS configuration is not yet supported\n"); + + gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; + +- if (rel15_ul->dmrs_config_type == 0) { ++ if (rel15_ul->dmrs_config_type == 0) ++ { + // if no data in dmrs cdm group is 1 only even REs have no data + // if no data in dmrs cdm group is 2 both odd and even REs have no data + nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*6)); + } +- else { ++ else ++ { + nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*4)); + } +- } else { ++ } ++ else ++ { + nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; + } + +@@ -1260,16 +2063,16 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + //---------------------------------------------------------- + //--------------------- RBs extraction --------------------- + //---------------------------------------------------------- +- if (nb_re_pusch > 0) { +- ++ if (nb_re_pusch > 0) ++ { + start_meas(&gNB->ulsch_rbs_extraction_stats); +- nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF, +- gNB->pusch_vars[ulsch_id], +- slot, +- symbol, +- dmrs_symbol_flag, +- rel15_ul, +- frame_parms); ++ nr_ulsch_extract_rbs(gNB->common_vars.rxdataF, ++ gNB->pusch_vars[ulsch_id], ++ slot, ++ symbol, ++ dmrs_symbol_flag, ++ rel15_ul, ++ frame_parms); + stop_meas(&gNB->ulsch_rbs_extraction_stats); + + //---------------------------------------------------------- +@@ -1280,8 +2083,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + gNB->ulsch[ulsch_id], + symbol, + dmrs_symbol_flag, +- rel15_ul->rb_size, +- rel15_ul->dmrs_config_type); ++ nb_re_pusch, ++ rel15_ul->nrOfLayers, ++ rel15_ul->rb_size); + + if (gNB->pusch_vars[ulsch_id]->cl_done==0) { + nr_ulsch_channel_level(gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, +@@ -1312,9 +2116,14 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, + gNB->pusch_vars[ulsch_id]->rxdataF_comp, ++ #ifdef SUPPORT_PMI_MATRIC + (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, ++ #else ++ NULL, ++ #endif + frame_parms, + symbol, ++ nb_re_pusch, + dmrs_symbol_flag, + rel15_ul->qam_mod_order, + rel15_ul->nrOfLayers, +@@ -1327,19 +2136,37 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + gNB->pusch_vars[ulsch_id]->rxdataF_comp, + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, ++ #ifdef SUPPORT_PMI_MATRIC ++ (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, ++ #else ++ NULL, ++ #endif ++ rel15_ul->nrOfLayers, + symbol, +- rel15_ul->rb_size); ++ rel15_ul->rb_size, ++ nb_re_pusch); ++ ++ if (rel15_ul->nrOfLayers == 2)//Apply zero forcing for 2 Tx layers ++ nr_ulsch_zero_forcing_rx_2layers(gNB->pusch_vars[ulsch_id]->rxdataF_comp, ++ gNB->pusch_vars[ulsch_id]->ul_ch_mag0, ++ gNB->pusch_vars[ulsch_id]->ul_ch_magb0, ++ gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, ++ rel15_ul->rb_size, ++ frame_parms->nb_antennas_rx, ++ rel15_ul->qam_mod_order, ++ gNB->pusch_vars[ulsch_id]->log2_maxh, ++ symbol, ++ nb_re_pusch); + stop_meas(&gNB->ulsch_mrc_stats); + +- // transform precoding = 0 means enabled +- if (rel15_ul->transform_precoding == 0) { +- +- #ifdef __AVX2__ ++ if (rel15_ul->transformPrecoder == transformPrecoder_enabled) ++ { ++ #ifdef __AVX2__ + // For odd number of resource blocks need byte alignment to multiple of 8 + int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); +- #else ++ #else + int nb_re_pusch2 = nb_re_pusch; +- #endif ++ #endif + + // perform IDFT operation on the compensated rxdata if transform precoding is enabled + nr_idft(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * nb_re_pusch2], nb_re_pusch); +@@ -1351,7 +2178,8 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + //---------------------------------------------------------- + /* In case PTRS is enabled then LLR will be calculated after PTRS symbols are processed * + * otherwise LLR are calculated for each symbol based upon DMRS channel estimates only. */ +- if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { ++ if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) ++ { + start_meas(&gNB->ulsch_ptrs_processing_stats); + nr_pusch_ptrs_processing(gNB, + frame_parms, +@@ -1370,14 +2198,17 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, + /*-------------------- LLRs computation -------------------------------------------------------------*/ + /*-----------------------------------------------------------------------------------------------------*/ + start_meas(&gNB->ulsch_llr_stats); +- nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], +- gNB->pusch_vars[ulsch_id]->ul_ch_mag0, +- gNB->pusch_vars[ulsch_id]->ul_ch_magb0, +- &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order], +- rel15_ul->rb_size, +- gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], +- symbol, +- rel15_ul->qam_mod_order); ++ for (aatx=0; aatx < rel15_ul->nrOfLayers; aatx++) ++ { ++ nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aatx*frame_parms->nb_antennas_rx][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], ++ gNB->pusch_vars[ulsch_id]->ul_ch_mag0[aatx*frame_parms->nb_antennas_rx], ++ gNB->pusch_vars[ulsch_id]->ul_ch_magb0[aatx*frame_parms->nb_antennas_rx], ++ &gNB->pusch_vars[ulsch_id]->llr_layers[aatx][rxdataF_ext_offset * rel15_ul->qam_mod_order], ++ rel15_ul->rb_size, ++ gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], ++ symbol, ++ rel15_ul->qam_mod_order); ++ } + stop_meas(&gNB->ulsch_llr_stats); + rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol]; + } +diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +index bf96a76106..ad41ebf3d6 100644 +--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c ++++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +@@ -64,7 +64,7 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, + //---------------------------------------------------------------------------------------------- + + void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, +- int32_t **ul_ch_mag, ++ int32_t *ul_ch_mag, + int16_t *ulsch_llr, + uint32_t nb_rb, + uint32_t nb_re, +@@ -110,12 +110,12 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, + + #if defined(__x86_64__) || defined(__i386__) + #ifdef __AVX2__ +- ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; ++ ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; + #else +- ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; ++ ch_mag = (__m128i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; + #endif + #elif defined(__arm__) +- ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; ++ ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; + #endif + + #ifdef __AVX2__ +@@ -231,8 +231,8 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, + //---------------------------------------------------------------------------------------------- + + void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, +- int32_t **ul_ch_mag, +- int32_t **ul_ch_magb, ++ int32_t *ul_ch_mag, ++ int32_t *ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_rb, + uint32_t nb_re, +@@ -265,15 +265,15 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + + #if defined(__x86_64__) || defined(__i386__) + #ifdef __AVX2__ +- ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; +- ch_magb = (__m256i*)&ul_ch_magb[0][(symbol*(off+(nb_rb*12)))]; ++ ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; ++ ch_magb = (__m256i*)&ul_ch_magb[(symbol*(off+(nb_rb*12)))]; + #else +- ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)]; +- ch_magb = (__m128i*)&ul_ch_magb[0][(symbol*nb_rb*12)]; ++ ch_mag = (__m128i*)&ul_ch_mag[(symbol*nb_rb*12)]; ++ ch_magb = (__m128i*)&ul_ch_magb[(symbol*nb_rb*12)]; + #endif + #elif defined(__arm__) +- ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; +- ch_magb = (int16x8_t*)&ul_ch_magb[0][(symbol*nb_rb*12)]; ++ ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; ++ ch_magb = (int16x8_t*)&ul_ch_magb[(symbol*nb_rb*12)]; + #endif + + #ifdef __AVX2__ +@@ -471,8 +471,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + + + void nr_ulsch_compute_llr(int32_t *rxdataF_comp, +- int32_t **ul_ch_mag, +- int32_t **ul_ch_magb, ++ int32_t *ul_ch_mag, ++ int32_t *ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_rb, + uint32_t nb_re, +diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c +index 65ae288252..2cb7609d62 100644 +--- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c ++++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c +@@ -148,7 +148,7 @@ short filt8_dcr0_h[8]= { + 0,4096,8192,12288,16384,0,0,0}; + + short filt8_l1[8] = { +-24576,16384,0,0,0,0,0,0}; ++24576,16384,8192,0,0,0,0,0}; + + short filt8_ml1[8] = { + -8192,0,8192,16384,8192,0,0,0}; +@@ -163,10 +163,10 @@ short filt8_mm1[8]= { + 0,0,0,0,8192,16384,8192,0}; + + short filt8_dcl1[8]= { +-0,0,0,16384,12288,8192,4096,0}; ++0,0,16384,12288,8192,4096,0,0}; + + short filt8_dcr1[8]= { +-0,0,0,0,4096,8192,12288,16384}; ++0,0,0,4096,8192,12288,16384,0}; + + short filt8_dcl1_h[8]= { + 0,16384,12288,8192,4096,0,0,0}; +diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +index 945dc51673..a293eec6d8 100644 +--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c ++++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +@@ -258,6 +258,15 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, + Ilbrm = 0; + Tbslbrm = 950984; //max tbs + Coderate = 0.0; ++ ++ #if 0 ++ harq_process->a[0] = 0x31; ++ for (int i = 1; i < harq_process->pusch_pdu.pusch_data.tb_size; i++) ++ { ++ harq_process->a[i] = (i&0xff); ++ } ++ #endif ++ + trace_NRpdu(DIRECTION_UPLINK, harq_process->a, harq_process->pusch_pdu.pusch_data.tb_size, 0, WS_C_RNTI, 0, 0, 0,0, 0); + /////////// + ///////////////////////////////////////////////////////////////////////////////////////// +diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +index 99dc2b658e..5d76e654ba 100644 +--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c ++++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +@@ -98,13 +98,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + uint8_t thread_id, + int gNB_id) { + +- LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); ++ LOG_I(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); + + uint32_t available_bits; + uint8_t cwd_index, l; + uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; +- int16_t **tx_layers; +- int32_t **txdataF; ++ + int8_t Wf[2], Wt[2], l_prime[2], delta; + uint8_t nb_dmrs_re_per_rb; + int ap, i; +@@ -112,6 +111,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + + NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; + NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id]; ++ int16_t **tx_layers = (int16_t **)pusch_ue->txdataF_layers; ++ int16_t **tx_precoding = (int16_t **)pusch_ue->txdataF_precoding; ++ int32_t **txdataF = UE->common_vars.txdataF; + + uint8_t num_of_codewords = 1; // tmp assumption + int Nid_cell = 0; +@@ -148,9 +150,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + + nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; + +- LOG_D(PHY,"ulsch %x : start_rb %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", +- rnti,start_rb,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); +- ++ LOG_I(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", ++ rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); ++ + // TbD num_of_mod_symbols is set but never used + N_RE_prime = NR_NB_SC_PER_RB*number_of_symbols - nb_dmrs_re_per_rb*number_dmrs_symbols - N_PRB_oh; + harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb*num_of_codewords; +@@ -236,8 +238,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + /////////////////////////ULSCH layer mapping///////////////////////// + /////////// + +- tx_layers = (int16_t **)pusch_ue->txdataF_layers; +- + nr_ue_layer_mapping(UE->ulsch[thread_id][gNB_id], + Nl, + available_bits/mod_order, +@@ -257,7 +257,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + int16_t *dmrs_seq = NULL; + + // if transform precoding is enbaled (value 0) +- if (pusch_pdu->transform_precoding == 0) { ++ if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { + + uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; + uint32_t y_offset = 0; +@@ -315,10 +315,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); + #endif + +- } +- else +- memcpy(ulsch_ue->y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); +- ++ } + + /////////// + //////////////////////////////////////////////////////////////////////// +@@ -328,145 +325,233 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, + /////////////////////////ULSCH RE mapping///////////////////////// + /////////// + +- txdataF = UE->common_vars.txdataF; +- +- for (ap=0; ap< Nl; ap++) { +- +- uint8_t k_prime = 0; +- uint16_t m = 0; +- +- +- #ifdef DEBUG_PUSCH_MAPPING ++ for (ap=0; ap< Nl; ap++) ++ { ++ uint8_t k_prime = 0; ++ uint16_t m = 0; ++ ++ #ifdef DEBUG_PUSCH_MAPPING + printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); +- #endif +- +- +- +- // DMRS params for this ap +- get_Wt(Wt, ap, dmrs_type); +- get_Wf(Wf, ap, dmrs_type); +- delta = get_delta(ap, dmrs_type); +- +- for (l=start_symbol; l> l) & 0x01) { +- is_dmrs_sym = 1; +- +- // transform precoding disabled (value 1) +- if (pusch_pdu->transform_precoding == 1){ +- +- if (dmrs_type == pusch_dmrs_type1) +- dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; +- else +- dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; +- +- // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part +- // Perform this on gold sequence, not required when SC FDMA operation is done, +- LOG_D(PHY,"DMRS in symbol %d\n",l); +- nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated +- +- } else { +- dmrs_idx = 0; +- } +- +- +- } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { +- +- AssertFatal(pusch_pdu->transform_precoding == 1, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); ++ #endif + +- if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { +- is_ptrs_sym = 1; +- nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); ++ // DMRS params for this ap ++ get_Wt(Wt, ap, dmrs_type); ++ get_Wf(Wf, ap, dmrs_type); ++ delta = get_delta(ap, dmrs_type); ++ ++ for (l=start_symbol; l> l) & 0x01) ++ { ++ is_dmrs_sym = 1; ++ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) ++ { ++ if (dmrs_type == pusch_dmrs_type1) ++ dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; ++ else ++ dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; ++ ++ // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part ++ // Perform this on gold sequence, not required when SC FDMA operation is done, ++ LOG_D(PHY,"DMRS in symbol %d\n",l); ++ nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated ++ } ++ else ++ { ++ dmrs_idx = 0; ++ } ++ } ++ else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) ++ { ++ AssertFatal(pusch_pdu->transformPrecoder == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); ++ ++ if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) ++ { ++ is_ptrs_sym = 1; ++ nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); ++ } + } +- } + +- for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) { ++ for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) ++ { ++ uint8_t is_dmrs = 0; ++ uint8_t is_ptrs = 0; + +- uint8_t is_dmrs = 0; +- uint8_t is_ptrs = 0; ++ sample_offsetF = l*frame_parms->ofdm_symbol_size + k; + +- sample_offsetF = l*frame_parms->ofdm_symbol_size + k; +- +- if (is_dmrs_sym) { +- if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) +- is_dmrs = 1; +- } else if (is_ptrs_sym) { ++ if (is_dmrs_sym) ++ { ++ if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) ++ is_dmrs = 1; ++ } ++ else if (is_ptrs_sym) ++ { + is_ptrs = is_ptrs_subcarrier(k, +- rnti, +- ap, +- dmrs_type, +- K_ptrs, +- nb_rb, +- pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, +- start_sc, +- frame_parms->ofdm_symbol_size); +- } +- +- if (is_dmrs == 1) { +- // if transform precoding is enabled +- if (pusch_pdu->transform_precoding == 0) { +- +- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; ++ rnti, ++ ap, ++ dmrs_type, ++ K_ptrs, ++ nb_rb, ++ pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, ++ start_sc, ++ frame_parms->ofdm_symbol_size); ++ } ++ ++ if (is_dmrs == 1) ++ { ++ if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; ++ } ++ else ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; ++ } ++ ++ #ifdef DEBUG_PUSCH_MAPPING ++ printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", ++ ap, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); ++ #endif ++ ++ dmrs_idx++; ++ k_prime++; ++ k_prime&=1; ++ n+=(k_prime)?0:1; ++ } ++ else if (is_ptrs == 1) ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; ++ ++ ptrs_idx++; ++ } ++ else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) ++ { ++ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[ap])[m<<1]; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[ap])[(m<<1) + 1]; ++ } ++ else ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; ++ } ++ ++ #ifdef DEBUG_PUSCH_MAPPING ++ printf("DATA: layer %d\t m %d\t l %d \t k %d \t txdataF: %d %d\n", ++ ap, m, l, k, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); ++ #endif ++ ++ m++; ++ } ++ else ++ { ++ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = 0; ++ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = 0; ++ } ++ ++ if (++k >= frame_parms->ofdm_symbol_size) ++ { ++ k -= frame_parms->ofdm_symbol_size; ++ } ++ } //for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) ++ }//for (l=start_symbol; lnb_antennas_tx; ap++) ++ { ++ for (int l=start_symbol; lTpmi; + +- } else { +- +- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; +- ++ if (pmi == 0) {//unitary Precoding ++ if(ap< pusch_pdu->nrOfLayers) ++ memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], ++ (void*)&tx_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)], ++ NR_NB_SC_PER_RB*sizeof(int32_t)); ++ else ++ memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], ++ 0, ++ NR_NB_SC_PER_RB*sizeof(int32_t)); ++ ++ k += NR_NB_SC_PER_RB; ++ if (k >= frame_parms->ofdm_symbol_size) { ++ k -= frame_parms->ofdm_symbol_size; ++ } ++ } ++ else ++ { ++ //get the precoding matrix weights: ++ char *W_prec; ++ switch (frame_parms->nb_antennas_tx) ++ { ++ case 1://1 antenna port ++ W_prec = nr_W_1l_2p[pmi][ap]; ++ break; ++ case 2://2 antenna ports ++ if (pusch_pdu->nrOfLayers == 1)//1 layer ++ W_prec = nr_W_1l_2p[pmi][ap]; ++ else//2 layers ++ W_prec = nr_W_2l_2p[pmi][ap]; ++ break; ++ case 4://4 antenna ports ++ if (pusch_pdu->nrOfLayers == 1)//1 layer ++ W_prec = nr_W_1l_4p[pmi][ap]; ++ else if (pusch_pdu->nrOfLayers == 2)//2 layers ++ W_prec = nr_W_2l_4p[pmi][ap]; ++ else if (pusch_pdu->nrOfLayers == 3)//3 layers ++ W_prec = nr_W_3l_4p[pmi][ap]; ++ else//4 layers ++ W_prec = nr_W_4l_4p[pmi][ap]; ++ break; ++ default: ++ LOG_D(PHY,"Precoding 1,2, or 4 antenna ports are currently supported\n"); ++ W_prec = nr_W_1l_2p[pmi][ap]; ++ break; + } + +- #ifdef DEBUG_PUSCH_MAPPING +- printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", +- dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); +- #endif +- +- +- dmrs_idx++; +- k_prime++; +- k_prime&=1; +- n+=(k_prime)?0:1; +- +- } else if (is_ptrs == 1) { +- +- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; +- +- ptrs_idx++; +- +- } else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { +- +- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; +- +- #ifdef DEBUG_PUSCH_MAPPING +- printf("m %d\t l %d \t k %d \t txdataF: %d %d\n", +- m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); +- #endif +- +- m++; +- +- } else { +- +- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = 0; +- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = 0; +- +- } ++ for (int i=0; iofdm_symbol_size + k; ++ int32_t precodatatx_F = nr_layer_precoder(tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); ++ ((int16_t*)txdataF[ap])[(re_offset<<1)] = ((int16_t *) &precodatatx_F)[0]; ++ ((int16_t*)txdataF[ap])[(re_offset<<1) + 1] = ((int16_t *) &precodatatx_F)[1]; ++ ++ if (++k >= frame_parms->ofdm_symbol_size) ++ { ++ k -= frame_parms->ofdm_symbol_size; ++ } ++ } ++ } ++ } //RB loop ++ } // symbol loop ++ }// port loop + +- if (++k >= frame_parms->ofdm_symbol_size) +- k -= frame_parms->ofdm_symbol_size; +- } +- } +- } +- } ++ } //for (cwd_index = 0;cwd_index < num_of_codewords; cwd_index++) + + NR_UL_UE_HARQ_t *harq_process_ulsch=NULL; + harq_process_ulsch = UE->ulsch[thread_id][gNB_id][0]->harq_processes[harq_pid]; +diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h +index 11b5112a6c..600ba07cb3 100644 +--- a/openair1/PHY/defs_gNB.h ++++ b/openair1/PHY/defs_gNB.h +@@ -479,7 +479,7 @@ typedef struct { + /// \brief Cross-correlation of two UE signals. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: symbol [0..] +- int32_t **rho; ++ int32_t ***rho; + /// \f$\log_2(\max|H_i|^2)\f$ + int16_t log2_maxh; + /// \brief Magnitude of Uplink Channel first layer (16QAM level/First 64QAM level). +@@ -509,6 +509,10 @@ typedef struct { + /// \brief llr values. + /// - first index: ? [0..1179743] (hard coded) + int16_t *llr; ++ /// \brief llr values per layer. ++ /// - first index: ? [0..3] (hard coded) ++ /// - first index: ? [0..1179743] (hard coded) ++ int16_t **llr_layers; + /// DMRS symbol index, to be updated every DMRS symbol within a slot. + uint8_t dmrs_symbol; + // PTRS symbol index, to be updated every PTRS symbol within a slot. +diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h +index 69978f5548..02988b590a 100644 +--- a/openair1/PHY/defs_nr_UE.h ++++ b/openair1/PHY/defs_nr_UE.h +@@ -229,6 +229,9 @@ typedef struct { + typedef struct { + /// TX buffers for multiple layers + int32_t *txdataF_layers[NR_MAX_NB_LAYERS]; ++ ++ /// TX buffers for UE-spec transmission ++ int32_t *txdataF_precoding[NR_MAX_NB_LAYERS]; + } NR_UE_PUSCH; + + typedef struct { +diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h +index c385d323e3..fbe094f41c 100644 +--- a/openair1/PHY/defs_nr_common.h ++++ b/openair1/PHY/defs_nr_common.h +@@ -93,7 +93,7 @@ + #define NR_MAX_CSET_DURATION 3 + + #define NR_MAX_NB_RBG 18 +-#define NR_MAX_NB_LAYERS 2 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) ++#define NR_MAX_NB_LAYERS 4 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) + #define NR_MAX_NB_CODEWORDS 2 + #define NR_MAX_NB_HARQ_PROCESSES 16 + #define NR_MAX_PDSCH_ENCODED_LENGTH (NR_MAX_NB_RB*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8*NR_MAX_NB_LAYERS) // 8 is the maximum modulation order (it was 950984 before !!) +@@ -104,11 +104,11 @@ + #define MAX_NUM_NR_DLSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) + #define MAX_NR_DLSCH_PAYLOAD_BYTES (MAX_NUM_NR_DLSCH_SEGMENTS*1056) + +-#define MAX_NUM_NR_ULSCH_SEGMENTS 34 ++#define MAX_NUM_NR_ULSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) + #define MAX_NR_ULSCH_PAYLOAD_BYTES (MAX_NUM_NR_ULSCH_SEGMENTS*1056) + +-#define MAX_NUM_NR_CHANNEL_BITS (14*273*12*8) // 14 symbols, 273 RB +-#define MAX_NUM_NR_RE (14*273*12) ++#define MAX_NUM_NR_CHANNEL_BITS (4*14*273*12*8) // 14 symbols, 273 RB ++#define MAX_NUM_NR_RE (4*14*273*12) + #define NR_RX_NB_TH 1 + #define NR_NB_TH_SLOT 2 + +diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c +index d8fa11d157..640a0740ef 100644 +--- a/openair1/SCHED_NR/nr_ru_procedures.c ++++ b/openair1/SCHED_NR/nr_ru_procedures.c +@@ -526,7 +526,8 @@ void nr_fep0(RU_t *ru, int first_half) { + end_symbol = NR_SYMBOLS_PER_SLOT; + } + +- LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d\n", proc->tti_rx, first_half, start_symbol, end_symbol); ++ LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d, nb_antennas_rx = %d,N_TA_offset = %d\n", ++ proc->tti_rx, first_half, start_symbol, end_symbol,fp->nb_antennas_rx,ru->N_TA_offset); + // printf("fep0: slot %d\n",slot); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 1); +diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c +index 1685e206ae..63c708e565 100644 +--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c ++++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c +@@ -253,13 +253,13 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { + // if all segments are done + if (rdata->nbSegments == ulsch_harq->processedSegments) { + if (decodeSuccess) { +- LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", ++ LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", + gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); + ulsch_harq->status = SCH_IDLE; + ulsch_harq->round = 0; + ulsch->harq_mask &= ~(1 << rdata->harq_pid); + +- LOG_D(PHY, "ULSCH received ok \n"); ++ LOG_I(PHY, "ULSCH received ok \n"); + nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); + //dumpsig=1; + } else { +@@ -281,7 +281,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { + } + ulsch_harq->handled = 1; + +- LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); ++ LOG_I(PHY, "ULSCH %d in error\n",rdata->ulsch_id); + nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1,0); + } + /* +@@ -365,6 +365,14 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); ++ ++ ++ nr_ulsch_layer_demapping(gNB->pusch_vars[ULSCH_id]->llr, ++ pusch_pdu->nrOfLayers, ++ pusch_pdu->qam_mod_order, ++ G, ++ gNB->pusch_vars[ULSCH_id]->llr_layers); ++ + //---------------------------------------------------------- + //------------------- ULSCH unscrambling ------------------- + //---------------------------------------------------------- +@@ -731,7 +739,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { + (ulsch_harq->slot == slot_rx) && + (ulsch_harq->handled == 0)){ + +- LOG_D(PHY, "PUSCH detection started in frame %d slot %d\n", ++ LOG_I(PHY, "PUSCH detection started in frame %d slot %d\n", + frame_rx,slot_rx); + int num_dmrs=0; + for (int s=0;srx_pusch_stats); + no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); + if (no_sig) { +- LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); ++ LOG_I(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); + nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); + return 1; + } +@@ -783,7 +791,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { + dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot) + gNB->pusch_thres) { + NR_gNB_SCH_STATS_t *stats=get_ulsch_stats(gNB,ulsch); + +- LOG_D(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, ++ LOG_I(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, + dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot), + dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres); + gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot; +diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +index f6e4d90bee..8e1df435c3 100644 +--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c ++++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +@@ -157,7 +157,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ + for (i = 0; i < ul_config->number_pdus; ++i){ + + AssertFatal(ul_config->ul_config_list[i].pdu_type <= FAPI_NR_UL_CONFIG_TYPES,"pdu_type %d out of bounds\n",ul_config->ul_config_list[i].pdu_type); +- LOG_D(PHY, "In %s: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); ++ LOG_I(PHY, "In %s i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); + + uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type, current_harq_pid, gNB_id = 0; + /* PRACH */ +@@ -180,6 +180,8 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ + if (harq_process_ul_ue){ + + nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &harq_process_ul_ue->pusch_pdu; ++ ++ LOG_I(PHY, "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n", __FUNCTION__, i, pusch_config_pdu->nrOfLayers,pusch_config_pdu->num_dmrs_cdm_grps_no_data); + + memcpy(pusch_pdu, pusch_config_pdu, sizeof(nfapi_nr_ue_pusch_pdu_t)); + +diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +index 940931694c..0a0a9cc2f9 100644 +--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c ++++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +@@ -270,9 +270,12 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, + AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN); +- +- memset(ue->common_vars.txdataF[0], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); +- ++ ++ for(int i=0; i< ue->frame_parms.nb_antennas_tx; ++i) ++ { ++ memset(ue->common_vars.txdataF[i], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); ++ } ++ + LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); + + +diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c +index 1eb6027936..d5a1054654 100644 +--- a/openair1/SIMULATION/NR_PHY/dlsim.c ++++ b/openair1/SIMULATION/NR_PHY/dlsim.c +@@ -768,7 +768,7 @@ int main(int argc, char **argv) + + prepare_scd(scd); + +- fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); ++ fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); + + /* RRC parameter validation for secondaryCellGroup */ + fix_scd(scd); +diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c +index 94aea36a67..fb8b4295ae 100644 +--- a/openair1/SIMULATION/NR_PHY/ulschsim.c ++++ b/openair1/SIMULATION/NR_PHY/ulschsim.c +@@ -137,6 +137,7 @@ int main(int argc, char **argv) + uint16_t nb_symb_sch = 12; + uint16_t nb_rb = 50; + uint8_t Imcs = 9; ++ uint8_t Nl = 1; + + double DS_TDL = .03; + +@@ -150,7 +151,7 @@ int main(int argc, char **argv) + randominit(0); + + //while ((c = getopt(argc, argv, "df:hpg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:")) != -1) { +- while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:")) != -1) { ++ while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:W:")) != -1) { + switch (c) { + /*case 'f': + write_output_file = 1; +@@ -251,7 +252,7 @@ int main(int argc, char **argv) + case 'y': + n_tx = atoi(optarg); + +- if ((n_tx == 0) || (n_tx > 2)) { ++ if ((n_tx == 0) || (n_tx > 4)) { + printf("Unsupported number of TX antennas %d. Exiting.\n", n_tx); + exit(-1); + } +@@ -261,7 +262,7 @@ int main(int argc, char **argv) + case 'z': + n_rx = atoi(optarg); + +- if ((n_rx == 0) || (n_rx > 2)) { ++ if ((n_rx == 0) || (n_rx > 4)) { + printf("Unsupported number of RX antennas %d. Exiting.\n", n_rx); + exit(-1); + } +@@ -299,6 +300,10 @@ int main(int argc, char **argv) + printf("Illegal PBCH phase (0-3) got %d\n", pbch_phase); + break;*/ + ++ case 'W': ++ Nl = atoi(optarg); ++ break; ++ + case 'm': + Imcs = atoi(optarg); + #ifdef DEBUG_NR_ULSCHSIM +@@ -335,13 +340,14 @@ int main(int argc, char **argv) + printf("-z Number of RX antennas used in UE\n"); + //printf("-i Relative strength of first intefering eNB (in dB) - cell_id mod 3 = 1\n"); + //printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n"); ++ printf("-W number of layer\n"); + printf("-M Multiple SSB positions in burst\n"); + printf("-N Nid_cell\n"); + printf("-R N_RB_UL\n"); + printf("-F Input filename (.txt format) for RX conformance testing\n"); +- printf("-m\n"); +- printf("-l\n"); +- printf("-r\n"); ++ printf("-m MCS\n"); ++ printf("-l number of symbol\n"); ++ printf("-r number of RB\n"); + //printf("-O oversampling factor (1,2,4,8,16)\n"); + //printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); + //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); +@@ -359,8 +365,8 @@ int main(int argc, char **argv) + snr1 = snr0 + 10; + + gNB2UE = new_channel_desc_scm(n_tx, +- n_rx, +- channel_model, ++ n_rx, ++ channel_model, + 61.44e6, //N_RB2sampling_rate(N_RB_DL), + 40e6, //N_RB2channel_bandwidth(N_RB_DL), + DS_TDL, +@@ -426,8 +432,7 @@ int main(int argc, char **argv) + uint8_t length_dmrs = 1; + uint8_t N_PRB_oh; + uint16_t N_RE_prime,code_rate; +- unsigned char mod_order; +- uint8_t Nl = 1; ++ unsigned char mod_order; + uint8_t rvidx = 0; + uint8_t UE_id = 0; + +@@ -437,9 +442,14 @@ int main(int argc, char **argv) + + NR_UE_ULSCH_t *ulsch_ue = UE->ulsch[0][0][0]; + ++ if ((Nl==4)||(Nl==3)) ++ { ++ nb_re_dmrs = nb_re_dmrs*2; ++ } ++ + mod_order = nr_get_Qm_ul(Imcs, 0); + code_rate = nr_get_code_rate_ul(Imcs, 0); +- available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1); ++ available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, Nl); + TBS = nr_compute_tbs(mod_order,code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, 0, Nl); + + printf("\nAvailable bits %u TBS %u mod_order %d\n", available_bits, TBS, mod_order); +diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c +index 69316d6b88..b6cfae3fe1 100644 +--- a/openair1/SIMULATION/NR_PHY/ulsim.c ++++ b/openair1/SIMULATION/NR_PHY/ulsim.c +@@ -282,7 +282,7 @@ int main(int argc, char **argv) + int gNB_id = 0; + int ap; + int tx_offset; +- int32_t txlev=0; ++ int32_t txlev_sum = 0, atxlev[4]; + int start_rb = 0; + int UE_id =0; // [hna] only works for UE_id = 0 because NUMBER_OF_NR_UE_MAX is set to 1 (phy_init_nr_gNB causes segmentation fault) + float target_error_rate = 0.01; +@@ -307,7 +307,7 @@ int main(int argc, char **argv) + uint16_t ptrsSymbPerSlot = 0; + uint16_t ptrsRePerSymb = 0; + +- uint8_t transform_precoding = 1; // 0 - ENABLE, 1 - DISABLE ++ uint8_t transformPrecoder = transformPrecoder_disabled; // 0 - ENABLE, 1 - DISABLE + uint8_t num_dmrs_cdm_grps_no_data = 1; + uint8_t mcs_table = 0; + +@@ -329,7 +329,7 @@ int main(int argc, char **argv) + /* initialize the sin-cos table */ + InitSinLUT(); + +- while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:ikl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z")) != -1) { ++ while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:kl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z:W:")) != -1) { + printf("handling optarg %c\n",c); + switch (c) { + +@@ -363,8 +363,8 @@ int main(int argc, char **argv) + scg_fd = fopen(optarg, "r"); + + if (scg_fd == NULL) { +- printf("Error opening %s\n", optarg); +- exit(-1); ++ printf("Error opening %s\n", optarg); ++ exit(-1); + } + + break; +@@ -437,6 +437,10 @@ int main(int argc, char **argv) + case 'm': + Imcs = atoi(optarg); + break; ++ ++ case 'W': ++ precod_nbr_layers = atoi(optarg); ++ break; + + case 'n': + n_trials = atoi(optarg); +@@ -485,9 +489,9 @@ int main(int argc, char **argv) + case 'y': + n_tx = atoi(optarg); + +- if ((n_tx == 0) || (n_tx > 2)) { +- printf("Unsupported number of tx antennas %d\n", n_tx); +- exit(-1); ++ if ((n_tx == 0) || (n_tx > 4)) { ++ printf("Unsupported number of tx antennas %d\n", n_tx); ++ exit(-1); + } + + break; +@@ -496,8 +500,8 @@ int main(int argc, char **argv) + n_rx = atoi(optarg); + + if ((n_rx == 0) || (n_rx > 8)) { +- printf("Unsupported number of rx antennas %d\n", n_rx); +- exit(-1); ++ printf("Unsupported number of rx antennas %d\n", n_rx); ++ exit(-1); + } + + break; +@@ -506,8 +510,8 @@ int main(int argc, char **argv) + input_fd = fopen(optarg, "r"); + + if (input_fd == NULL) { +- printf("Problem with filename %s\n", optarg); +- exit(-1); ++ printf("Problem with filename %s\n", optarg); ++ exit(-1); + } + + break; +@@ -568,11 +572,11 @@ int main(int argc, char **argv) + + case 'Z': + +- transform_precoding = 0; // enabled ++ transformPrecoder = transformPrecoder_enabled; + num_dmrs_cdm_grps_no_data = 2; + mcs_table = 3; + +- printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transform_precoding); ++ printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transformPrecoder); + + break; + +@@ -611,6 +615,7 @@ int main(int argc, char **argv) + printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n"); + printf("-Q If -F used, read parameters from file\n"); + printf("-Z If -Z is used, SC-FDMA or transform precoding is enabled in Uplink \n"); ++ printf("-W Num of layer for PUSCH\n"); + exit(-1); + break; + +@@ -713,7 +718,7 @@ int main(int argc, char **argv) + + prepare_scd(scd); + +- fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); ++ fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); + + // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); + +@@ -724,9 +729,9 @@ int main(int argc, char **argv) + + gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; + // common configuration +- rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,0, 0, NULL); ++ rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,0, 0, NULL); + // UE dedicated configuration +- rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); ++ rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + frame_parms->nb_antennas_tx = n_tx; + frame_parms->nb_antennas_rx = n_rx; + nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; +@@ -870,14 +875,18 @@ int main(int argc, char **argv) + uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); + printf("num dmrs sym %d\n",number_dmrs_symbols); + uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; +- +- // if transform precoding is enabled +- if (transform_precoding == 0) { ++ ++ if ((frame_parms->nb_antennas_tx==4)&&(precod_nbr_layers==4)) ++ { ++ num_dmrs_cdm_grps_no_data = 2; ++ } ++ ++ if (transformPrecoder == transformPrecoder_enabled) { + + AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); + + int8_t index = get_index_for_dmrs_lowpapr_seq((NR_NB_SC_PER_RB/2) * nb_rb); +- AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); ++ AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + + dmrs_config_type = pusch_dmrs_type1; + +@@ -886,7 +895,7 @@ int main(int argc, char **argv) + + nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; + +- unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1); ++ unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, precod_nbr_layers); + unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); + + +@@ -1082,14 +1091,14 @@ int main(int argc, char **argv) + pusch_pdu->mcs_table = mcs_table; + pusch_pdu->target_code_rate = code_rate; + pusch_pdu->qam_mod_order = mod_order; +- pusch_pdu->transform_precoding = transform_precoding; ++ pusch_pdu->transformPrecoder = transformPrecoder; + pusch_pdu->data_scrambling_id = *scc->physCellId; +- pusch_pdu->nrOfLayers = 1; ++ pusch_pdu->nrOfLayers = precod_nbr_layers; + pusch_pdu->ul_dmrs_symb_pos = l_prime_mask; + pusch_pdu->dmrs_config_type = dmrs_config_type; + pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; + pusch_pdu->scid = 0; +- pusch_pdu->dmrs_ports = 1; ++ pusch_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; + pusch_pdu->resource_alloc = 1; + pusch_pdu->rb_start = start_rb; +@@ -1109,7 +1118,7 @@ int main(int argc, char **argv) + pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; + + // if transform precoding is enabled +- if (transform_precoding == 0) { ++ if (transformPrecoder == transformPrecoder_enabled) { + + pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; // U as defined in 38.211 section 6.4.1.1.1.2 + pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; // V as defined in 38.211 section 6.4.1.1.1.2 +@@ -1167,10 +1176,10 @@ int main(int argc, char **argv) + ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t)); + ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; + +- ul_config.ul_config_list[0].pusch_config_pdu.transform_precoding = transform_precoding; ++ ul_config.ul_config_list[0].pusch_config_pdu.transformPrecoder = transformPrecoder; + + // if transform precoding is enabled +- if (transform_precoding == 0) { ++ if (transformPrecoder == transformPrecoder_enabled) { + + ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_group_number = *scc->physCellId % 30;// U as defined in 38.211 section 6.4.1.1.1.2 + ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;// V as defined in 38.211 section 6.4.1.1.1.2 +@@ -1198,28 +1207,54 @@ int main(int argc, char **argv) + LOG_D(PHY, "Sending Uplink data \n"); + nr_ue_pusch_common_procedures(UE, + slot, +- &UE->frame_parms,1); +- +- if (n_trials==1) { +- LOG_M("txsig0.m","txs0", UE->common_vars.txdata[0],frame_parms->samples_per_subframe*10,1,1); ++ &UE->frame_parms, ++ frame_parms->nb_antennas_tx); ++ ++ ++ if (n_trials==1) ++ { ++ LOG_M("txsig0.m","txs0", &UE->common_vars.txdata[0][slot_offset],slot_length,1,1); + LOG_M("txsig0F.m","txs0F", UE->common_vars.txdataF[0],frame_parms->ofdm_symbol_size*14,1,1); ++ if (precod_nbr_layers > 1) ++ { ++ LOG_M("txsig1.m","txs1", &UE->common_vars.txdata[1][slot_offset],slot_length,1,1); ++ LOG_M("txsig1F.m","txs1F", UE->common_vars.txdataF[1],frame_parms->ofdm_symbol_size*14,1,1); ++ if (precod_nbr_layers==4) ++ { ++ LOG_M("txsig2.m","txs2", &UE->common_vars.txdata[2][slot_offset],slot_length,1,1); ++ LOG_M("txsig3.m","txs3", &UE->common_vars.txdata[3][slot_offset],slot_length,1,1); ++ ++ LOG_M("txsig2F.m","txs2F", UE->common_vars.txdataF[2],frame_parms->ofdm_symbol_size*14,1,1); ++ LOG_M("txsig3F.m","txs3F", UE->common_vars.txdataF[3],frame_parms->ofdm_symbol_size*14,1,1); ++ } ++ } + } + /////////// + //////////////////////////////////////////////////// + tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); +- +- txlev = signal_energy(&UE->common_vars.txdata[0][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], ++ txlev_sum = 0; ++ for (int aa=0; aanb_antennas_tx; aa++) ++ { ++ atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], + frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); +- } +- else n_trials = 1; +- +- if (input_fd == NULL ) { ++ ++ txlev_sum += atxlev[aa]; ++ ++ if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,atxlev[aa],10*log10((double)atxlev[aa]),txlev_sum); ++ } ++ } ++ else ++ { ++ n_trials = 1; ++ } + +- sigma_dB = 10 * log10((double)txlev * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; ++ if (input_fd == NULL ) ++ { ++ sigma_dB = 10 * log10((double)txlev_sum * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; + sigma = pow(10,sigma_dB/10); + + +- if(n_trials==1) printf("sigma %f (%f dB), txlev %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev),(double)(double) ++ if(n_trials==1) printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev_sum),(double)(double) + frame_parms->ofdm_symbol_size/(12*nb_rb)); + + for (i=0; imax_Doppler == 0) { ++ if (UE2gNB->max_Doppler == 0) ++ { + multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); + } else { + multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); + } +- for (i=0; inb_antennas_rx; ap++) { ++ for (i=0; inb_antennas_rx; ap++) ++ { ++ if (channel_model == AWGN) ++ { ++ double H_awgn[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 ++ {0.0, 1.0, 0.0, 0.0}, //rx 1 ++ {0.0, 0.0, 1.0, 0.0}, //rx 2 ++ {0.0, 0.0, 0.0, 1.0}};//rx 3 ++ #if 0 ++ double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 ++ {0.5, 1.0, 0.5, 0.25}, //rx 1 ++ {0.25, 0.5, 1.0, 0.5}, //rx 2 ++ {0.125, 0.25, 0.5, 1.0}};//rx 3 ++ #endif ++ // sum up signals from different Tx antennas ++ r_re[ap][i] = 0; ++ r_im[ap][i] = 0; ++ ++ for (int aa=0; aaofdm_symbol_size/(12*nb_rb))) - SNR;; ++ sigma = pow(10,sigma_dB/10); ++ + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); ++ ++ #if 0 ++ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i])); // convert to fixed point ++ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i])); ++ ++ ++ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) ] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i) ]; // convert to fixed point ++ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i)+1 ]; ++ #endif ++ + /* Add phase noise if enabled */ + if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)], +@@ -1250,7 +1324,8 @@ int main(int argc, char **argv) + } /*End input_fd */ + + +- if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { ++ if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) ++ { + set_ptrs_symb_idx(&ptrsSymPos, + pusch_pdu->nr_of_symbols, + pusch_pdu->start_symbol_index, +@@ -1268,24 +1343,37 @@ int main(int argc, char **argv) + gNB->UL_INFO.rx_ind.number_of_pdus = 0; + gNB->UL_INFO.crc_ind.number_crcs = 0; + +- phy_procedures_gNB_common_RX(gNB, frame, slot); ++ phy_procedures_gNB_common_RX(gNB, frame, slot); + +- ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); ++ ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); + +- if (n_trials==1 && round==0) { ++ if (n_trials==1 && round==0) ++ { + LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1); + +- LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0]+start_symbol*frame_parms->ofdm_symbol_size,nb_symb_sch*frame_parms->ofdm_symbol_size,1,1); +- ++ LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],14*frame_parms->ofdm_symbol_size,1,1); ++ if (precod_nbr_layers > 1) ++ { ++ LOG_M("rxsig1.m","rx1",&gNB->common_vars.rxdata[1][slot_offset],slot_length,1,1); ++ LOG_M("rxsigF1.m","rxsF1",gNB->common_vars.rxdataF[1],14*frame_parms->ofdm_symbol_size,1,1); ++ if (precod_nbr_layers==4) ++ { ++ LOG_M("rxsig2.m","rx2",&gNB->common_vars.rxdata[2][slot_offset],slot_length,1,1); ++ LOG_M("rxsig3.m","rx3",&gNB->common_vars.rxdata[3][slot_offset],slot_length,1,1); ++ ++ LOG_M("rxsigF2.m","rxsF2",gNB->common_vars.rxdataF[2],14*frame_parms->ofdm_symbol_size,1,1); ++ LOG_M("rxsigF3.m","rxsF3",gNB->common_vars.rxdataF[3],14*frame_parms->ofdm_symbol_size,1,1); ++ } ++ } + } + + + if (n_trials == 1 && round==0) { +-#ifdef __AVX2__ ++ #ifdef __AVX2__ + int off = ((nb_rb&1) == 1)? 4:0; +-#else ++ #else + int off = 0; +-#endif ++ #endif + + LOG_M("rxsigF0_ext.m","rxsF0_ext", + &gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); +@@ -1298,11 +1386,77 @@ int main(int argc, char **argv) + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_comp.m","rxsF0_comp", + &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); +- LOG_M("chmagF0.m","chmF0", +- &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); +- LOG_M("chmagbF0.m","chmbF0", +- &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); +- if (n_rx == 2) { ++ LOG_M("chmagF0.m","chmF0", ++ &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("chmagbF0.m","chmbF0", ++ &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF0_llrlayers0.m","rxsF0_llrlayers0", ++ &gNB->pusch_vars[0]->llr_layers[0][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ ++ if (precod_nbr_layers==2) ++ { ++ LOG_M("rxsigF1_ext.m","rxsF1_ext", ++ &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ ++ LOG_M("chestF3.m","chF3", ++ &gNB->pusch_vars[0]->ul_ch_estimates[3][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); ++ ++ LOG_M("chestF3_ext.m","chF3_ext", ++ &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], ++ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ ++ LOG_M("rxsigF2_comp.m","rxsF2_comp", ++ &gNB->pusch_vars[0]->rxdataF_comp[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ ++ LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", ++ &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ ++ } ++ ++ if (precod_nbr_layers==4) ++ { ++ LOG_M("rxsigF1_ext.m","rxsF1_ext", ++ &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF2_ext.m","rxsF2_ext", ++ &gNB->pusch_vars[0]->rxdataF_ext[2][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF3_ext.m","rxsF3_ext", ++ &gNB->pusch_vars[0]->rxdataF_ext[3][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ ++ LOG_M("chestF5.m","chF5", ++ &gNB->pusch_vars[0]->ul_ch_estimates[5][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); ++ LOG_M("chestF10.m","chF10", ++ &gNB->pusch_vars[0]->ul_ch_estimates[10][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); ++ LOG_M("chestF15.m","chF15", ++ &gNB->pusch_vars[0]->ul_ch_estimates[15][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); ++ ++ ++ LOG_M("chestF5_ext.m","chF5_ext", ++ &gNB->pusch_vars[0]->ul_ch_estimates_ext[5][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], ++ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("chestF10_ext.m","chF10_ext", ++ &gNB->pusch_vars[0]->ul_ch_estimates_ext[10][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], ++ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("chestF15_ext.m","chF15_ext", ++ &gNB->pusch_vars[0]->ul_ch_estimates_ext[15][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], ++ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ ++ ++ LOG_M("rxsigF4_comp.m","rxsF4_comp", ++ &gNB->pusch_vars[0]->rxdataF_comp[4][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF8_comp.m","rxsF8_comp", ++ &gNB->pusch_vars[0]->rxdataF_comp[8][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF12_comp.m","rxsF12_comp", ++ &gNB->pusch_vars[0]->rxdataF_comp[12][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); ++ LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", ++ &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ LOG_M("rxsigF0_llrlayers2.m","rxsF0_llrlayers2", ++ &gNB->pusch_vars[0]->llr_layers[2][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ LOG_M("rxsigF0_llrlayers3.m","rxsF0_llrlayers3", ++ &gNB->pusch_vars[0]->llr_layers[3][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ } ++ ++ #if 0 ++ if (n_rx == 2) { + LOG_MM("rxsigF0_comp.m","rxsF1_comp", + &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_ext.m","rxsF1_ext", +@@ -1349,9 +1503,10 @@ int main(int argc, char **argv) + LOG_MM("chmagbF0.m","chmbF3", + &gNB->pusch_vars[0]->ul_ch_magb[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + } ++ #endif + + LOG_M("rxsigF0_llr.m","rxsF0_llr", +- &gNB->pusch_vars[0]->llr[0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); ++ &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + } + //////////////////////////////////////////////////////////// + +diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +index 3f4be9dd58..7e5be9eeba 100644 +--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c ++++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +@@ -2708,6 +2708,9 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, + LOG_D(NR_MAC,"dci_pdu->srs_resource_indicator.nbits %d\n",dci_pdu->srs_resource_indicator.nbits); + // Precoding info and number of layers + long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); ++ ++ pusch_antenna_ports = *pusch_Config->maxRank; ++ + dci_pdu->precoding_information.nbits=0; + if (pusch_Config && + pusch_Config->txConfig != NULL){ +diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +index c23d4bb073..963723725f 100644 +--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c ++++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +@@ -190,7 +190,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + else + transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; + } +- ++ pusch_config_pdu->transformPrecoder = transformPrecoder; + + /* PRECOD_NBR_LAYERS */ + if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)); +@@ -198,11 +198,12 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + + if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)){ + +- uint8_t n_antenna_port = 0; //FIXME!!! ++ uint8_t n_antenna_port = mac->phy_config.config_req.carrier_config.num_tx_ant; + + if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits + +- if (n_antenna_port == 4){ // 4 antenna port and the higher layer parameter txConfig = codebook ++ if (n_antenna_port == 4) ++ { // 4 antenna port and the higher layer parameter txConfig = codebook + + // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4 + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) +@@ -212,54 +213,56 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; + } + } + + // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1 + if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) + || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) +- && (*pusch_Config->maxRank == 1)){ ++ && (*pusch_Config->maxRank == 1)) ++ { + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; + } + } + } + +- if (n_antenna_port == 4){ // 2 antenna port and the higher layer parameter txConfig = codebook ++ if (n_antenna_port == 2) ++ { // 2 antenna port and the higher layer parameter txConfig = codebook + // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2 +- if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)){ +- ++ if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) ++ { + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; + } + + } +@@ -267,16 +270,17 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1 + if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) + || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) +- && (*pusch_Config->maxRank == 1)){ ++ && (*pusch_Config->maxRank == 1)) ++ { + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; + } + + if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ + pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18]; +- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; ++ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; + } + + } +@@ -285,9 +289,9 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + + /*-------------------- Changed to enable Transform precoding in RF SIM------------------------------------------------*/ + +- /*if (pusch_config_pdu->transform_precoding == transform_precoder_enabled) { ++ /*if (pusch_config_pdu->transformPrecoder == transformPrecoder_enabled) { + +- pusch_config_dedicated->transform_precoder = transform_precoder_enabled; ++ pusch_config_dedicated->transform_precoder = transformPrecoder_enabled; + + if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) { + +@@ -309,7 +313,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con + + } + } else +- pusch_config_dedicated->transform_precoder = transform_precoder_disabled;*/ ++ pusch_config_dedicated->transformPrecoder = ttransformPrecoder_disabled;*/ + } + + // todo: this function shall be reviewed completely because of the many comments left by the author +@@ -342,7 +346,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf + } + long *max_length = NULL; + long *dmrs_type = NULL; +- LOG_D(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); ++ LOG_I(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); + + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) { + max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength; +@@ -353,7 +357,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf + dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type; + } + +- LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); ++ LOG_I(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && + (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC +@@ -369,35 +373,32 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf + } + + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && +- (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11 ++ (dmrs_type == NULL) && (max_length == NULL)) ++ { // tables 7.3.1.1.2-8/9/10/11 ++ ++ if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)) ++ { ++ rank = pusch_config_pdu->nrOfLayers; ++ } + + if (rank == 1) { +- pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC +- pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val); //TBC ++ pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; ++ pusch_config_pdu->dmrs_ports =1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val)); + } + + if (rank == 2){ +- pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC +- pusch_config_pdu->dmrs_ports = 0; //FIXME +- //pusch_config_pdu->dmrs_ports[0] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?0:2):0; +- //pusch_config_pdu->dmrs_ports[1] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?2:3):1; ++ pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; ++ pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val> 2)?0x5:0xc):0x3; + } + + if (rank == 3){ +- pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC +- pusch_config_pdu->dmrs_ports = 0; //FIXME +- //pusch_config_pdu->dmrs_ports[0] = 0; +- //pusch_config_pdu->dmrs_ports[1] = 1; +- //pusch_config_pdu->dmrs_ports[2] = 2; ++ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; ++ pusch_config_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = 2; //TBC +- pusch_config_pdu->dmrs_ports = 0; //FIXME +- //pusch_config_pdu->dmrs_ports[0] = 0; +- //pusch_config_pdu->dmrs_ports[1] = 1; +- //pusch_config_pdu->dmrs_ports[2] = 2; +- //pusch_config_pdu->dmrs_ports[3] = 3; ++ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; ++ pusch_config_pdu->dmrs_ports = ((1<n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME + } + } +- LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); ++ LOG_I(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); + } + + // Configuration of Msg3 PDU according to clauses: +@@ -542,6 +543,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1; + pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; + pusch_config_pdu->nrOfLayers = 1; ++ pusch_config_pdu->Tpmi = 0; + pusch_config_pdu->rnti = rnti; + NR_BWP_UplinkCommon_t *initialUplinkBWP; + if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; +@@ -634,7 +636,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + pusch_config_pdu->scid = 0; + + // Transform precoding according to 6.1.3 UE procedure for applying transform precoding on PUSCH in 38.214 +- pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out ++ pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out + + // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214 + pusch_config_pdu->resource_alloc = (mac->cg) ? pusch_Config->resourceAllocation : 1; +@@ -680,7 +682,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + + /* Transform precoding */ + if (rnti_type != NR_RNTI_CS || (rnti_type == NR_RNTI_CS && dci->ndi == 1)) { +- pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); ++ pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); + } + + /*DCI format-related configuration*/ +@@ -716,7 +718,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + + /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/ + +- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { ++ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) { + + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + +@@ -761,7 +763,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + pusch_config_pdu->mcs_index = dci->mcs; + + /* MCS TABLE */ +- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { ++ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_Table : NULL, 0, *dci_format, rnti_type, target_ss, false); + } else { + pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, 1, *dci_format, rnti_type, target_ss, false); +@@ -798,9 +800,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + mappingtype, add_pos, dmrslength, + pusch_config_pdu->start_symbol_index, + mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); +- if ((mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) +- pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; +- else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) ++ if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) ++ { ++ if (*dci_format != NR_UL_DCI_FORMAT_0_1) ++ { ++ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; ++ } ++ } ++ else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)) + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + + // Num PRB Overhead from PUSCH-ServingCellConfig +@@ -821,7 +828,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, + mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup && + mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB && + mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { +- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { ++ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + nfapi_nr_ue_ptrs_ports_t ptrs_ports_list; + pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list; + valid_ptrs_setup = set_ul_ptrs_values(mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup, +@@ -909,6 +916,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in + + fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id); + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) ++ LOG_I(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); + mac->if_module->scheduled_response(&scheduled_response); + } + else { +@@ -1022,6 +1030,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in + + fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, rx_frame, rx_slot, ul_info->thread_id); + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){ ++ LOG_I(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); + mac->if_module->scheduled_response(&scheduled_response); + } + pthread_mutex_lock(&ul_config->mutex_ul_config); +diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c +index 1cb3fdb708..d9c98852a3 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/config.c ++++ b/openair2/LAYER2/NR_MAC_gNB/config.c +@@ -388,7 +388,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts + cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts; + AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n"); + cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG; +- LOG_I(NR_MAC,"Set TX/RX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); ++ LOG_I(NR_MAC,"Set RX antenna number to %d, Set TX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,cfg->carrier_config.num_rx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); + AssertFatal(cfg->carrier_config.num_tx_ant.value > 0,"carrier_config.num_tx_ant.value %d !\n",cfg->carrier_config.num_tx_ant.value ); + cfg->num_tlv++; + cfg->num_tlv++; +diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +index 6ac7f3f82e..5de36bb2db 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c ++++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +@@ -977,9 +977,9 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, + pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); + pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); + if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) +- pusch_pdu->transform_precoding = 1; ++ pusch_pdu->transformPrecoder = 1; + else +- pusch_pdu->transform_precoding = 0; ++ pusch_pdu->transformPrecoder = 0; + pusch_pdu->data_scrambling_id = *scc->physCellId; + pusch_pdu->nrOfLayers = 1; + pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); +diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +index abc007197d..9cbbe7d9a1 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c ++++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +@@ -1139,13 +1139,14 @@ void nr_schedule_ue_spec(module_id_t module_id, + dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; + LOG_D(NR_MAC, + "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " +- "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", ++ "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", + frame, + slot, + dci_payload.frequency_domain_assignment.val, + pdsch_pdu->rbStart, + pdsch_pdu->rbSize, + pdsch_pdu->BWPSize, ++ pdsch_pdu->nrOfLayers, + dci_payload.time_domain_assignment.val, + dci_payload.vrb_to_prb_mapping.val, + dci_payload.mcs, +diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +index f1005cea70..8f7c856a30 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c ++++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +@@ -405,6 +405,7 @@ void nr_preprocessor_phytest(module_id_t module_id, + + uint32_t target_ul_mcs = 9; + uint32_t target_ul_bw = 50; ++uint32_t target_ul_Nl = 1; + uint64_t ulsch_slot_bitmap = (1 << 8); + bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot) + { +@@ -446,15 +447,21 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ + + const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; + const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; +- const uint8_t num_dmrs_cdm_grps_no_data = 1; ++ uint8_t num_dmrs_cdm_grps_no_data = 1; ++ if ((target_ul_Nl==4)||(target_ul_Nl==3)) ++ { ++ num_dmrs_cdm_grps_no_data = 2; ++ } ++ + /* we want to avoid a lengthy deduction of DMRS and other parameters in + * every TTI if we can save it, so check whether dci_format, TDA, or + * num_dmrs_cdm_grps_no_data has changed and only then recompute */ + NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; + if (ps->time_domain_allocation != tda + || ps->dci_format != dci_format ++ || ps->nrOfLayers != target_ul_Nl + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) +- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data, ps); ++ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); + + uint16_t rbStart = 0; + uint16_t rbSize; +@@ -525,6 +532,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ + sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; + + /* Calculate TBS from MCS */ ++ ps->nrOfLayers = target_ul_Nl; + sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); + sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); + if (ps->pusch_Config->tp_pi2BPSK +@@ -539,7 +547,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ + ps->N_PRB_DMRS * ps->num_dmrs_symb, + 0, // nb_rb_oh + 0, +- 1 /* NrOfLayers */) ++ ps->nrOfLayers /* NrOfLayers */) + >> 3; + + /* mark the corresponding RBs as used */ +diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +index 1c0cb0353e..4583da876f 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c ++++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +@@ -355,6 +355,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, + long dci_format, + int tda, + uint8_t num_dmrs_cdm_grps_no_data, ++ uint8_t nrOfLayers, + NR_pusch_semi_static_t *ps) + { + ps->dci_format = dci_format; +@@ -371,11 +372,11 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, + + ps->pusch_Config = ubwp?ubwp->bwp_Dedicated->pusch_Config->choice.setup:(ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); + if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) +- ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; ++ ps->transformPrecoder = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; + else +- ps->transform_precoding = *ps->pusch_Config->transformPrecoder; ++ ps->transformPrecoder = *ps->pusch_Config->transformPrecoder; + const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; +- if (ps->transform_precoding) ++ if (ps->transformPrecoder) + ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_Table : NULL, + 0, + ps->dci_format, +@@ -392,6 +393,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, + num_dmrs_cdm_grps_no_data = 2; // in case of transform precoding - no Data sent in DMRS symbol + } + ++ ps->nrOfLayers = nrOfLayers; + ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; + + /* DMRS calculations */ +@@ -689,8 +691,21 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, + "Non Codebook configuration non supported\n"); + dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS + } ++ AssertFatal((pusch_pdu->Tpmi==0), "unsupport Tpmi\n"); ++ dci_pdu_rel15->precoding_information.val= 0; ++ if (pusch_pdu->nrOfLayers == 2) ++ { ++ dci_pdu_rel15->precoding_information.val = 4; ++ } ++ else if (pusch_pdu->nrOfLayers == 4) ++ { ++ dci_pdu_rel15->precoding_information.val = 11; ++ } ++ ++ // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 + // Antenna Ports +- dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank ++ dci_pdu_rel15->antenna_ports.val = 0; ++ + // DMRS sequence initialization + dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid; + break; +@@ -699,11 +714,14 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, + } + + LOG_D(NR_MAC, +- "%s() ULDCI type 0 payload: freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n", ++ "%s() ULDCI type 0 payload: dci_format %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, precoding_information.val %d antenna_ports.val %d mcs %d tpc %d ndi %d rv %d\n", + __func__, ++ dci_format, + dci_pdu_rel15->frequency_domain_assignment.val, + dci_pdu_rel15->time_domain_assignment.val, + dci_pdu_rel15->frequency_hopping_flag.val, ++ dci_pdu_rel15->precoding_information.val, ++ dci_pdu_rel15->antenna_ports.val, + dci_pdu_rel15->mcs, + dci_pdu_rel15->tpc, + dci_pdu_rel15->ndi, +diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +index 9a6fa32b5f..269d6c5359 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c ++++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +@@ -905,7 +905,7 @@ bool allocate_ul_retransmission(module_id_t module_id, + NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + int rbStart = 0; // wrt BWP start + const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); +- ++ const uint8_t nrOfLayers = 1; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; + const int tda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); +@@ -926,8 +926,9 @@ bool allocate_ul_retransmission(module_id_t module_id, + + if (ps->time_domain_allocation != tda + || ps->dci_format != dci_format ++ || ps->nrOfLayers != nrOfLayers + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) +- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); ++ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); + LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); + } else { + /* the retransmission will use a different time domain allocation, check +@@ -939,7 +940,7 @@ bool allocate_ul_retransmission(module_id_t module_id, + rbSize++; + NR_pusch_semi_static_t temp_ps; + int dci_format = get_dci_format(sched_ctrl); +- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, &temp_ps); ++ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, &temp_ps); + uint32_t new_tbs; + uint16_t new_rbSize; + bool success = nr_find_nb_rb(retInfo->Qm, +@@ -1094,7 +1095,7 @@ void pf_ul(module_id_t module_id, + if (max_num_ue < 0) + return; + +- LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d\n", min_rb, rbStart); ++ LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", min_rb, rbStart, ps->num_dmrs_cdm_grps_no_data); + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; + if (rbStart + min_rb >= bwpSize) { + LOG_W(NR_MAC, "cannot allocate continuous UL data for UE %d/RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d\n", +@@ -1106,13 +1107,15 @@ void pf_ul(module_id_t module_id, + /* we want to avoid a lengthy deduction of DMRS and other parameters in + * every TTI if we can save it, so check whether dci_format, TDA, or + * num_dmrs_cdm_grps_no_data has changed and only then recompute */ ++ const uint8_t nrOfLayers = 1; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; + int dci_format = get_dci_format(sched_ctrl); + const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + if (ps->time_domain_allocation != tda + || ps->dci_format != dci_format ++ || ps->nrOfLayers != nrOfLayers + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) +- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); ++ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data,nrOfLayers, ps); + NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + sched_pusch->mcs = 9; + update_ul_ue_R_Qm(sched_pusch, ps); +@@ -1125,7 +1128,7 @@ void pf_ul(module_id_t module_id, + ps->N_PRB_DMRS * ps->num_dmrs_symb, + 0, // nb_rb_oh + 0, +- 1 /* NrOfLayers */) ++ ps->nrOfLayers) + >> 3; + + /* Mark the corresponding RBs as used */ +@@ -1205,13 +1208,15 @@ void pf_ul(module_id_t module_id, + /* we want to avoid a lengthy deduction of DMRS and other parameters in + * every TTI if we can save it, so check whether dci_format, TDA, or + * num_dmrs_cdm_grps_no_data has changed and only then recompute */ ++ const uint8_t nrOfLayers = 1; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; + int dci_format = get_dci_format(sched_ctrl); + const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + if (ps->time_domain_allocation != tda + || ps->dci_format != dci_format ++ || ps->nrOfLayers != nrOfLayers + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) +- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); ++ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); + update_ul_ue_R_Qm(sched_pusch, ps); + + /* Calculate the current scheduling bytes and the necessary RBs */ +@@ -1473,7 +1478,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) + sched_ctrl->last_ul_slot = sched_pusch->slot; + + LOG_D(NR_MAC, +- "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", ++ "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", + frame, + slot, + rnti, +@@ -1486,6 +1491,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) + ps->nrOfSymbols, + ps->ul_dmrs_symb_pos, + sched_pusch->mcs, ++ ps->nrOfLayers, ++ ps->num_dmrs_cdm_grps_no_data, + sched_pusch->tb_size, + harq_id, + cur_harq->round, +@@ -1532,17 +1539,18 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) + pusch_pdu->qam_mod_order = sched_pusch->Qm; + pusch_pdu->mcs_index = sched_pusch->mcs; + pusch_pdu->mcs_table = ps->mcs_table; +- pusch_pdu->transform_precoding = ps->transform_precoding; ++ pusch_pdu->transformPrecoder = ps->transformPrecoder; + if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) + pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; + else + pusch_pdu->data_scrambling_id = *scc->physCellId; +- pusch_pdu->nrOfLayers = 1; ++ pusch_pdu->nrOfLayers = ps->nrOfLayers; ++ pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; + + /* FAPI: DMRS */ + pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos; + pusch_pdu->dmrs_config_type = ps->dmrs_config_type; +- if (pusch_pdu->transform_precoding) { // transform precoding disabled ++ if (pusch_pdu->transformPrecoder) { // transform precoding disabled + long *scramblingid=NULL; + if (ps->NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) + scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; +@@ -1562,7 +1570,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) + } + pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] + pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; +- pusch_pdu->dmrs_ports = 1; ++ pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); + + /* FAPI: Pusch Allocation in frequency domain */ + pusch_pdu->resource_alloc = 1; //type 1 +@@ -1588,7 +1596,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) + LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); + /* TRANSFORM PRECODING --------------------------------------------------------*/ + +- if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ ++ if (pusch_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled){ + + // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled + pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30; +diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +index 91221276b0..8a560580c9 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h ++++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +@@ -298,6 +298,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, + long dci_format, + int tda, + uint8_t num_dmrs_cdm_grps_no_data, ++ uint8_t nrOfLayers, + NR_pusch_semi_static_t *ps); + + uint8_t nr_get_tpc(int target, uint8_t cqi, int incr); +diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +index 27f42f4b1d..66b10dad42 100644 +--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h ++++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +@@ -318,13 +318,14 @@ typedef struct NR_sched_pucch { + typedef struct NR_pusch_semi_static_t { + int dci_format; + int time_domain_allocation; ++ uint8_t nrOfLayers; + uint8_t num_dmrs_cdm_grps_no_data; + + int startSymbolIndex; + int nrOfSymbols; + + NR_PUSCH_Config_t *pusch_Config; +- uint8_t transform_precoding; ++ uint8_t transformPrecoder; + uint8_t mcs_table; + + long mapping_type; +diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c +index ff6923429e..52d03b5e56 100755 +--- a/openair2/RRC/NR/MESSAGES/asn1_msg.c ++++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c +@@ -1867,6 +1867,7 @@ int16_t do_RRCReconfiguration( + // 1, + // 1, + // carrier->pdsch_AntennaPorts, ++ // carrier->pusch_AntennaPorts, + // carrier->initial_csi_index[ue_context_p->local_uid + 1], + // ue_context_pP->local_uid); + +diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h +index 9465b9b4b0..6a94450450 100644 +--- a/openair2/RRC/NR/nr_rrc_proto.h ++++ b/openair2/RRC/NR/nr_rrc_proto.h +@@ -79,6 +79,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco + int scg_id, + int servCellIndex, + int dl_antenna_ports, ++ int ul_antenna_ports, + int do_csirs, + int initial_csi_index, + int uid); +@@ -90,6 +91,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon + NR_RRCReconfiguration_IEs_t *reconfig, + NR_CellGroupConfig_t *secondaryCellGroup, + int dl_antenna_ports, ++ int ul_antenna_ports, + int do_csirs, + int initial_csi_index, + int uid); +diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c +index f9fce48f41..22e43cbb6a 100644 +--- a/openair2/RRC/NR/rrc_gNB_nsa.c ++++ b/openair2/RRC/NR/rrc_gNB_nsa.c +@@ -241,6 +241,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ + reconfig_ies, + ue_context_p->ue_context.secondaryCellGroup, + carrier->pdsch_AntennaPorts, ++ carrier->pusch_AntennaPorts, + carrier->do_CSIRS, + carrier->initial_csi_index[ue_context_p->local_uid + 1], + ue_context_p->local_uid); +@@ -250,6 +251,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ + reconfig_ies, + ue_context_p->ue_context.secondaryCellGroup, + carrier->pdsch_AntennaPorts, ++ carrier->pusch_AntennaPorts, + carrier->do_CSIRS, + carrier->initial_csi_index[ue_context_p->local_uid + 1], + ue_context_p->local_uid); +@@ -348,7 +350,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ + rrc_mac_config_req_gNB(rrc->module_id, + rrc->carrier.ssb_SubcarrierOffset, + rrc->carrier.pdsch_AntennaPorts, +- rrc->carrier.pusch_AntennaPorts, ++ rrc->carrier.pusch_AntennaPorts, + rrc->carrier.sib1_tda, + rrc->carrier.servingcellconfigcommon, + &rrc->carrier.mib, +diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c +index 980bd39c37..d03f361502 100644 +--- a/openair2/RRC/NR/rrc_gNB_reconfig.c ++++ b/openair2/RRC/NR/rrc_gNB_reconfig.c +@@ -55,6 +55,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco + int scg_id, + int servCellIndex, + int dl_antenna_ports, ++ int ul_antenna_ports, + int do_csirs, + int initial_csi_index, + int uid) { +@@ -745,14 +746,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco + pusch_Config->codebookSubset=calloc(1,sizeof(*pusch_Config->codebookSubset)); + *pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent; + pusch_Config->maxRank=calloc(1,sizeof(*pusch_Config->maxRank)); +- *pusch_Config->maxRank= 1; ++ *pusch_Config->maxRank= ul_antenna_ports; + pusch_Config->rbg_Size=NULL; + pusch_Config->uci_OnPUSCH=NULL; + pusch_Config->tp_pi2BPSK=NULL; + + /*------------------------------TRANSFORM PRECODING- -----------------------------------------------------------------------*/ + +- uint8_t transform_precoding = NR_PUSCH_Config__transformPrecoder_disabled; ++ uint8_t transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; + + // TBD: configure this from .conf file, Dedicated params cannot yet be configured in .conf file. + // Enable this to test transform precoding enabled from dedicated config. +@@ -764,13 +765,13 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco + + if (pusch_Config->transformPrecoder == NULL) { + if (servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder != NULL) +- transform_precoding = NR_PUSCH_Config__transformPrecoder_enabled; ++ transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled; + } + else +- transform_precoding = *pusch_Config->transformPrecoder; ++ transformPrecoder = *pusch_Config->transformPrecoder; + + +- if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled ) { ++ if (transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled ) { + /* Enable DMRS uplink config for transform precoding enabled */ + NR_DMRS_UplinkConfig->transformPrecodingEnabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingEnabled)); + NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity = NULL; +@@ -1348,6 +1349,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon + NR_RRCReconfiguration_IEs_t *reconfig, + NR_CellGroupConfig_t *secondaryCellGroup, + int dl_antenna_ports, ++ int ul_antenna_ports, + int do_csirs, + int initial_csi_index, + int uid) { +@@ -1363,6 +1365,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon + 1, + 1, + dl_antenna_ports, ++ ul_antenna_ports, + do_csirs, + initial_csi_index, + uid); +diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c +index 13945998d7..20faa86591 100644 +--- a/targets/ARCH/rfsimulator/simulator.c ++++ b/targets/ARCH/rfsimulator/simulator.c +@@ -429,7 +429,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp + if (!alreadyLocked) + pthread_mutex_lock(&Sockmutex); + +- LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); ++ LOG_D(HW,"sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt); + + for (int i=0; ibuf[i]; +@@ -623,7 +623,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest + } + + rfsimulator_state_t *t = device->priv; +- LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps); ++ LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld, nbAnt %d\n", nsamps, t->nextTimestamp+nsamps, nbAnt); + // deliver data from received data + // check if a UE is connected + int first_sock; +@@ -728,6 +728,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest + + for (int a=0; achannel_model != NULL ) // apply a channel model ++ { + rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a], + a, + ptr->channel_model, +@@ -735,11 +736,21 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest + t->nextTimestamp, + CirSize + ); +- else { // no channel modeling ++ } ++ else ++ { // no channel modeling ++ ++ #if 0 + double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 + {0.5, 1.0, 0.5, 0.25}, //rx 1 + {0.25, 0.5, 1.0, 0.5}, //rx 2 + {0.125, 0.25, 0.5, 1.0}};//rx 3 ++ #else ++ double H_awgn_mimo[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 ++ {0.0, 1.0, 0.0, 0.0},//rx 1 ++ {0.0, 0.0, 1.0, 0.0},//rx 2 ++ {0.0, 0.0, 0.0, 1.0}};//rx 3 ++ #endif + + sample_t *out=(sample_t *)samplesVoid[a]; + int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index c02155326b..1238b43c27 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -67,6 +67,7 @@ #define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" #define CONFIG_HLP_DLMCS_PHYTEST "Set the downlink MCS for PHYTEST mode\n" #define CONFIG_HLP_DLNL_PHYTEST "Set the downlink nrOfLayers for PHYTEST mode\n" +#define CONFIG_HLP_ULNL_PHYTEST "Set the uplink nrOfLayers for PHYTEST mode\n" #define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" #define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" #define CONFIG_HLP_ULMCS_PHYTEST "Set the uplink MCS for PHYTEST mode\n" diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h index 896c363cbf..a11572c0e1 100644 --- a/executables/nr-softmodem.h +++ b/executables/nr-softmodem.h @@ -23,6 +23,7 @@ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ {"m" , CONFIG_HLP_DLMCS_PHYTEST,0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ {"l" , CONFIG_HLP_DLNL_PHYTEST,0, uptr:&target_dl_Nl, defintval:0, TYPE_UINT, 0}, \ + {"L" , CONFIG_HLP_ULNL_PHYTEST,0, uptr:&target_ul_Nl, defintval:0, TYPE_UINT, 0}, \ {"t" , CONFIG_HLP_ULMCS_PHYTEST,0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ {"M" , CONFIG_HLP_DLBW_PHYTEST,0, uptr:&target_dl_bw, defintval:0, TYPE_UINT, 0}, \ {"T" , CONFIG_HLP_ULBW_PHYTEST,0, uptr:&target_ul_bw, defintval:0, TYPE_UINT, 0}, \ @@ -36,6 +37,7 @@ extern threads_t threads; extern uint32_t target_dl_mcs; extern uint32_t target_dl_Nl; +extern uint32_t target_ul_Nl; extern uint32_t target_ul_mcs; extern uint32_t target_dl_bw; extern uint32_t target_ul_bw; diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 60ff40abeb..a23f91b1dd 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -278,7 +278,7 @@ void processSlotTX(void *arg) { int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx); uint8_t gNB_id = 0; - LOG_D(PHY,"%d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); + LOG_D(PHY,"processSlotTX %d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){ // trigger L2 to run ue_scheduler thru IF module @@ -372,7 +372,8 @@ void processSlotRX(void *arg) { LOG_D(PHY, "Sending Uplink data \n"); nr_ue_pusch_common_procedures(UE, proc->nr_slot_tx, - &UE->frame_parms,1); + &UE->frame_parms, + UE->frame_parms.nb_antennas_tx); } if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) { diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index ad5ea982c9..57fd284601 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -465,8 +465,11 @@ int main( int argc, char **argv ) { memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE)); set_options(CC_id, UE[CC_id]); - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - + NR_DL_FRAME_PARMS *fp = &UE[CC_id]->frame_parms; + NR_UE_MAC_INST_t *mac = get_mac_inst(0); + + mac->phy_config.config_req.carrier_config.num_tx_ant = fp->nb_antennas_tx; + if (get_softmodem_params()->sa) { uint16_t nr_band = get_band(downlink_frequency[CC_id][0],uplink_frequency_offset[CC_id][0]); mac->nr_band = nr_band; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 0e923931ad..8b93417cb0 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -298,9 +298,10 @@ typedef struct uint8_t qam_mod_order; uint8_t mcs_index; uint8_t mcs_table; - uint8_t transform_precoding; + uint8_t transformPrecoder; uint16_t data_scrambling_id; uint8_t nrOfLayers; + uint8_t Tpmi; //DMRS uint16_t ul_dmrs_symb_pos; uint8_t dmrs_config_type; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 9d245446c8..58ff9037ce 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1208,9 +1208,10 @@ typedef struct uint8_t qam_mod_order; uint8_t mcs_index; uint8_t mcs_table; - uint8_t transform_precoding; + uint8_t transformPrecoder; uint16_t data_scrambling_id; uint8_t nrOfLayers; + uint8_t Tpmi; //DMRS uint16_t ul_dmrs_symb_pos; uint8_t dmrs_config_type; diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 7cb74f8562..473b0900bc 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -941,9 +941,10 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui push8(pusch_pdu->qam_mod_order, ppWritePackedMsg, end) && push8(pusch_pdu->mcs_index, ppWritePackedMsg, end) && push8(pusch_pdu->mcs_table, ppWritePackedMsg, end) && - push8(pusch_pdu->transform_precoding, ppWritePackedMsg, end) && + push8(pusch_pdu->transformPrecoder, ppWritePackedMsg, end) && push16(pusch_pdu->data_scrambling_id, ppWritePackedMsg, end) && push8(pusch_pdu->nrOfLayers, ppWritePackedMsg, end) && + push8(pusch_pdu->Tpmi, ppWritePackedMsg, end) && push16(pusch_pdu->ul_dmrs_symb_pos, ppWritePackedMsg, end) && push8(pusch_pdu->dmrs_config_type, ppWritePackedMsg, end) && push16(pusch_pdu->ul_dmrs_scrambling_id, ppWritePackedMsg, end) && @@ -4445,9 +4446,10 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(void *tlv, uint8_t **ppReadPacked pull8(ppReadPackedMsg, &pusch_pdu->qam_mod_order, end) && pull8(ppReadPackedMsg, &pusch_pdu->mcs_index, end) && pull8(ppReadPackedMsg, &pusch_pdu->mcs_table, end) && - pull8(ppReadPackedMsg, &pusch_pdu->transform_precoding, end) && + pull8(ppReadPackedMsg, &pusch_pdu->transformPrecoder, end) && pull16(ppReadPackedMsg, &pusch_pdu->data_scrambling_id, end) && pull8(ppReadPackedMsg, &pusch_pdu->nrOfLayers, end) && + pull8(ppReadPackedMsg, &pusch_pdu->Tpmi, end) && pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_symb_pos, end) && pull8(ppReadPackedMsg, &pusch_pdu->dmrs_config_type, end) && pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_scrambling_id, end) && diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index cd4848ea8c..2ac3230215 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -276,11 +276,21 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_mag = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); - pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(n_buf*sizeof(int32_t*) ); + pusch_vars[ULSCH_id]->rho = (int32_t ***)malloc16_clear(Prx*sizeof(int32_t**) ); + pusch_vars[ULSCH_id]->llr_layers = (int16_t **)malloc16(max_ul_mimo_layers*sizeof(int32_t *) ); for (i=0; irxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); + pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear( NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); + + for (int j=0; j< max_ul_mimo_layers; j++) + { + for (int k=0; krho[i][j*max_ul_mimo_layers+k]=(int32_t *)malloc16_clear( sizeof(int32_t) * fp->N_RB_UL*12*7*2 ); + } + } } for (i=0; iul_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); @@ -293,8 +303,12 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) ); + pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + } + + for (i=0; i< max_ul_mimo_layers; i++) + { + pusch_vars[ULSCH_id]->llr_layers[i] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear } pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear pusch_vars[ULSCH_id]->ul_valid_re_per_slot = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 4024ed1617..169db48e69 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -41,7 +41,7 @@ int nr_phy_init_RU(RU_t *ru) { int p; int re; - LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); + LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n",ru_if_types[ru->if_south],ru->nb_tx, ru->nb_rx); nfapi_nr_config_request_scf_t *cfg; ru->nb_log_antennas=0; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index b60e77e814..11fb6e7d61 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -124,7 +124,8 @@ void phy_init_nr_ue_PUSCH(NR_UE_PUSCH *const pusch, AssertFatal( pusch, "pusch==0" ); for (int i=0; itxdataF_layers[i] = (int32_t *)malloc16_clear(NR_MAX_PUSCH_ENCODED_LENGTH*sizeof(int32_t)); + pusch->txdataF_layers[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); + pusch->txdataF_precoding[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); } } @@ -143,7 +144,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, uint16_t N_n_scid[2] = {0,1}; // [HOTFIX] This is a temporary implementation of scramblingID0 and scramblingID1 which are given by DMRS-UplinkConfig int n_scid; abstraction_flag = 0; - LOG_I(PHY, "Initializing UE vars (abstraction %u) for gNB TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); + LOG_I(PHY, "Initializing UE vars (abstraction %u) for UE TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); //LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_gNB_INST); phy_init_nr_top(ue); // many memory allocation sizes are hard coded diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 1f164748bf..9a432e8615 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -110,7 +110,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, fr = filt8_r1; fmm = filt8_mm1; fml = filt8_ml1; - fmr = filt8_m1; + fmr = filt8_mm1; fdcl = filt8_dcl1; fdcr = filt8_dcr1; fdclh = filt8_dcl1_h; @@ -129,9 +129,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, //------------------generate DMRS------------------// - // transform precoding = 1 means disabled - if (pusch_pdu->transform_precoding == 1) { - nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, + if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { + nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], (1000+p), 0, nb_rb_pusch, (pusch_pdu->bwp_start + pusch_pdu->rb_start)*NR_NB_SC_PER_RB, pusch_pdu->dmrs_config_type); } else { // if transform precoding or SC-FDMA is enabled in Uplink @@ -291,7 +290,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); #endif - multadd_real_vector_complex_scalar(fml, + multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 4fed3a468f..87e4d57362 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -137,21 +137,22 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, @param nb_rb_pusch The number of RBs allocated (used for Resource Allocation Type 1 in NR) @param frame_parms, Pointer to frame descriptor structure */ -void nr_ulsch_extract_rbs_single(int32_t **rxdataF, - NR_gNB_PUSCH *pusch_vars, - int slot, - unsigned char symbol, - uint8_t is_dmrs_symbol, - nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_DL_FRAME_PARMS *frame_parms); +void nr_ulsch_extract_rbs(int32_t **rxdataF, + NR_gNB_PUSCH *pusch_vars, + int slot, + unsigned char symbol, + uint8_t is_dmrs_symbol, + nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_DL_FRAME_PARMS *frame_parms); void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext, NR_DL_FRAME_PARMS *frame_parms, NR_gNB_ULSCH_t **ulsch_gNB, - uint8_t symbol, - uint8_t start_symbol, - uint16_t nb_rb, - pusch_dmrs_type_t pusch_dmrs_type); + uint8_t symbol, + uint8_t is_dmrs_symbol, + uint32_t len, + uint8_t nrOfLayers, + uint16_t nb_rb); /** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal @param ul_ch_estimates_ext Channel estimates in allocated RBs @@ -185,9 +186,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, int **ul_ch_mag, int **ul_ch_magb, int **rxdataF_comp, - int **rho, + int ***rho, NR_DL_FRAME_PARMS *frame_parms, unsigned char symbol, + int length, uint8_t is_dmrs_symbol, unsigned char mod_order, uint8_t nrOfLayers, @@ -255,8 +257,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, @param mod_order modulation order */ void nr_ulsch_compute_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, int16_t *ulsch_llr, uint32_t nb_rb, uint32_t nb_re, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 4278338dbc..3ea19a9970 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -137,6 +137,38 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, #endif } +void nr_ulsch_layer_demapping(int16_t *llr_cw, + uint8_t Nl, + uint8_t mod_order, + uint32_t length, + int16_t **llr_layers) +{ + + switch (Nl) { + + case 1: + memcpy((void*)llr_cw, (void*)llr_layers[0], (length)*sizeof(int16_t)); + break; + + case 2: + case 3: + case 4: + for (int i=0; i<(length/Nl/mod_order); i++) + { + for (int l=0; lnumber_of_nr_ulsch_max;i++) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h index 80c10d74b1..0e660351ae 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h @@ -82,6 +82,12 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, uint32_t Nid, uint32_t n_RNTI); +void nr_ulsch_layer_demapping(int16_t *llr_cw, + uint8_t Nl, + uint8_t mod_order, + uint32_t length, + int16_t **llr_layers); + void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 28dd5ab219..8314c83ad9 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -302,26 +302,27 @@ void nr_idft(int32_t *z, uint32_t Msc_PUSCH) } -void nr_ulsch_extract_rbs_single(int32_t **rxdataF, - NR_gNB_PUSCH *pusch_vars, - int slot, - unsigned char symbol, - uint8_t is_dmrs_symbol, - nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_DL_FRAME_PARMS *frame_parms) +void nr_ulsch_extract_rbs(int32_t **rxdataF, + NR_gNB_PUSCH *pusch_vars, + int slot, + unsigned char symbol, + uint8_t is_dmrs_symbol, + nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_DL_FRAME_PARMS *frame_parms) { unsigned short start_re, re, nb_re_pusch; - unsigned char aarx; + unsigned char aarx, aatx; uint32_t rxF_ext_index = 0; uint32_t ul_ch0_ext_index = 0; uint32_t ul_ch0_index = 0; - uint8_t k_prime; - uint16_t n; + //uint8_t k_prime; + //uint16_t n; int16_t *rxF,*rxF_ext; int *ul_ch0,*ul_ch0_ext; - uint8_t delta = 0; + //uint8_t delta = 0; int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; + #ifdef DEBUG_RB_EXT printf("--------------------symbol = %d-----------------------\n", symbol); @@ -329,7 +330,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, #endif - uint8_t is_dmrs_re; + uint8_t is_data_re; start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB)%frame_parms->ofdm_symbol_size; nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; #ifdef __AVX2__ @@ -338,64 +339,95 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, int nb_re_pusch2 = nb_re_pusch; #endif - for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { + for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) + { rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 - - ul_ch0 = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available - - ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch2]; - - n = 0; - k_prime = 0; - rxF_ext_index = 0; - ul_ch0_ext_index = 0; - ul_ch0_index = 0; - - if (is_dmrs_symbol == 0) { + + if (is_dmrs_symbol == 0) + { // //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); - if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { + if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) + { memcpy1((void*)rxF_ext, (void*)&rxF[start_re*2], nb_re_pusch*sizeof(int32_t)); - } else { - int neg_length = frame_parms->ofdm_symbol_size-start_re; - int pos_length = nb_re_pusch-neg_length; + } + else + { + int neg_length = frame_parms->ofdm_symbol_size-start_re; + int pos_length = nb_re_pusch-neg_length; + memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); + memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); + } - memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); - memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); + #ifdef SUPPORT_PMI_MATRIC + for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) + #else + aatx = aarx; + #endif + { + ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; + + memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); } - memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); } - else { - for (re = 0; re < nb_re_pusch; re++) { + else + { + #ifdef SUPPORT_PMI_MATRIC + for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) + #else + aatx = aarx; + #endif + { + ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; - is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type)); + //n = 0; + //k_prime = 0; + rxF_ext_index = 0; + ul_ch0_ext_index = 0; + ul_ch0_index = 0; + + for (re = 0; re < nb_re_pusch; re++) + { + uint16_t k= start_re+re; + + is_data_re = allowed_xlsch_re_in_dmrs_symbol(k, start_re, frame_parms->ofdm_symbol_size, pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type); + + if (++k >= frame_parms->ofdm_symbol_size) + { + k -= frame_parms->ofdm_symbol_size; + } -#ifdef DEBUG_RB_EXT - printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); -#endif + #ifdef DEBUG_RB_EXT + printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); + #endif - /* save only data and respective channel estimates */ - if (is_dmrs_re == 0) { - rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); - rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); - ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; + /* save only data and respective channel estimates */ + if (is_data_re == 1) + { + if (aatx == aarx) + { + rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); + rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); + rxF_ext_index +=2; + } + + ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; + ul_ch0_ext_index++; -#ifdef DEBUG_RB_EXT - printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", + #ifdef DEBUG_RB_EXT + printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1], ul_ch0_ext_index, ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0], ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]); -#endif - ul_ch0_ext_index++; - rxF_ext_index +=2; - } else { - n += k_prime; - k_prime ^= 1; + #endif + } + ul_ch0_index++; } - ul_ch0_index++; } } } @@ -406,16 +438,19 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, NR_gNB_ULSCH_t **ulsch_gNB, uint8_t symbol, uint8_t is_dmrs_symbol, - unsigned short nb_rb, - pusch_dmrs_type_t pusch_dmrs_type) + uint32_t len, + uint8_t nrOfLayers, + unsigned short nb_rb) { #if defined(__x86_64__)||defined(__i386__) short rb, ch_amp; - unsigned char aarx; + unsigned char aarx,aatx; __m128i *ul_ch128, ch_amp128; + uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); + // Determine scaling amplitude based the symbol ch_amp = 1024*8; //((pilots) ? (ulsch_gNB[0]->sqrt_rho_b) : (ulsch_gNB[0]->sqrt_rho_a)); @@ -431,35 +466,26 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, int off = 0; #endif - for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) { - - ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; - - if (is_dmrs_symbol==1){ - if (pusch_dmrs_type == pusch_dmrs_type1) - nb_rb = nb_rb>>1; - else - nb_rb = (2*nb_rb)/3; - } - - for (rb=0;rbnb_antennas_rx; aarx++) + { + ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; + for (rb=0;rb < nb_rb_0;rb++) + { ul_ch128[0] = _mm_mulhi_epi16(ul_ch128[0], ch_amp128); ul_ch128[0] = _mm_slli_epi16(ul_ch128[0], 3); ul_ch128[1] = _mm_mulhi_epi16(ul_ch128[1], ch_amp128); ul_ch128[1] = _mm_slli_epi16(ul_ch128[1], 3); - if (is_dmrs_symbol) { - ul_ch128+=2; - } else { - ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); - ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); - ul_ch128+=3; - - } + ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); + ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); + ul_ch128+=3; } - } + } +} #endif } @@ -481,6 +507,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, int16_t x = factor2(len); int16_t y = (len)>>x; + + uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); #ifdef __AVX2__ int off = ((nb_rb&1) == 1)? 4:0; @@ -489,13 +517,16 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, #endif for (aatx = 0; aatx < nrOfLayers; aatx++) - for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { + { + for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) + { //clear average level avg128U = _mm_setzero_si128(); ul_ch128=(__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - for (rb = 0; rb < len/12; rb++) { + for (rb = 0; rb < nb_rb_0; rb++) + { avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[1], ul_ch128[1]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[2], ul_ch128[2]), x)); @@ -508,7 +539,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, ((int32_t*)&avg128U)[3]) / y; } - + } + _mm_empty(); _m_empty(); @@ -520,7 +552,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, int16x4_t *ul_ch128; symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; - + uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); for (aatx=0; aatxnb_antennas_rx; aarx++) { //clear average level @@ -529,7 +561,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, ul_ch128 = (int16x4_t *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*frame_parms->N_RB_UL*12]; - for (rb = 0; rb < nb_rb; rb++) { + for (rb = 0; rb < nb_rb_0; rb++) { // printf("rb %d : ",rb); // print_shorts("ch",&ul_ch128[0]); avg128U = vqaddq_s32(avg128U, vmull_s16(ul_ch128[0], ul_ch128[0])); @@ -568,14 +600,20 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, #endif } + + +//============================================================================================== +// Pre-processing for LLR computation +//============================================================================================== void nr_ulsch_channel_compensation(int **rxdataF_ext, int **ul_ch_estimates_ext, int **ul_ch_mag, int **ul_ch_magb, int **rxdataF_comp, - int **rho, + int ***rho, NR_DL_FRAME_PARMS *frame_parms, unsigned char symbol, + int length, uint8_t is_dmrs_symbol, unsigned char mod_order, uint8_t nrOfLayers, @@ -637,20 +675,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128={0},QAM_amp128b={0}; QAM_amp128b = _mm_setzero_si128(); - for (aatx=0; aatxnb_antennas_rx; aarx++) { - + for (aarx=0; aarxnb_antennas_rx; aarx++) + { ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ul_ch_mag128 = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ul_ch_mag128b = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; @@ -658,8 +700,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, rxdataF_comp128 = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - for (rb=0; rb2) { + for (rb=0; rb2) + { // get channel amplitude if not QPSK //print_shorts("ch:",(int16_t*)&ul_ch128[0]); @@ -679,6 +723,8 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128[0] = _mm_mulhi_epi16(ul_ch_mag128[0],QAM_amp128); ul_ch_mag128[0] = _mm_slli_epi16(ul_ch_mag128[0],1); + ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); + ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); // print_ints("ch: = ",(int32_t*)&mmtmpD0); // print_shorts("QAM_amp:",(int16_t*)&QAM_amp128); // print_shorts("mag:",(int16_t*)&ul_ch_mag128[0]); @@ -687,30 +733,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128b[1] = ul_ch_mag128[1]; ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128); ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],1); - - if (is_dmrs_symbol==0) { - mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); - mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); - mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); - - ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); - ul_ch_mag128b[2] = ul_ch_mag128[2]; - - ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); - ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); - } - - ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); - ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); - - - ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128b); + + ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128); ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); - if (is_dmrs_symbol==0) { - ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); - ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); - } + mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); + mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); + mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); + + ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); + ul_ch_mag128b[2] = ul_ch_mag128[2]; + + ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); + ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); + + + ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); + ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); + } // multiply by conjugated channel @@ -755,117 +795,157 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, // print_shorts("ch:",ul_ch128+1); // print_shorts("pack:",rxdataF_comp128+1); - if (is_dmrs_symbol==0) { - // multiply by conjugated channel - mmtmpD0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]); - // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) - mmtmpD1 = _mm_shufflelo_epi16(ul_ch128[2],_MM_SHUFFLE(2,3,0,1)); - mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); - mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate); - mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[2]); - // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit) - mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); - mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift); - mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); - mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); + // multiply by conjugated channel + mmtmpD0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]); + // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) + mmtmpD1 = _mm_shufflelo_epi16(ul_ch128[2],_MM_SHUFFLE(2,3,0,1)); + mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); + mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate); + mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[2]); + // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit) + mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); + mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift); + mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); + mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); - rxdataF_comp128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3); - // print_shorts("rx:",rxdataF128+2); - // print_shorts("ch:",ul_ch128+2); - // print_shorts("pack:",rxdataF_comp128+2); - - ul_ch128+=3; - ul_ch_mag128+=3; - ul_ch_mag128b+=3; - rxdataF128+=3; - rxdataF_comp128+=3; - } else { // we have a smaller PUSCH in symbols with pilots so skip last group of 4 REs and increment less - ul_ch128+=2; - ul_ch_mag128+=2; - ul_ch_mag128b+=2; - rxdataF128+=2; - rxdataF_comp128+=2; - } + rxdataF_comp128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3); + //print_shorts("rx:",rxdataF128+2); + //print_shorts("ch:",ul_ch128+2); + //print_shorts("pack:",rxdataF_comp128+2); + ul_ch128+=3; + ul_ch_mag128+=3; + ul_ch_mag128b+=3; + rxdataF128+=3; + rxdataF_comp128+=3; } } } if (rho) { + //we compute the Tx correlation matrix for each Rx antenna + //As an example the 2x2 MIMO case requires + //rho[aarx][nb_aatx*nb_aatx] = [cov(H_aarx_0,H_aarx_0) cov(H_aarx_0,H_aarx_1) + // cov(H_aarx_1,H_aarx_0) cov(H_aarx_1,H_aarx_1)], aarx=0,...,nb_antennas_rx-1 - for (aarx=0; aarxnb_antennas_rx; aarx++) { - rho128 = (__m128i *)&rho[aarx][symbol*frame_parms->N_RB_UL*12]; - ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_UL*12]; - ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_UL*12]; + int avg_rho_re[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; + int avg_rho_im[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; - for (rb=0; rbnb_antennas_rx; aarx++) + { + for (aatx=0; aatx < nrOfLayers; aatx++) + { + ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; + + for (int atx=0; atx< nrOfLayers; atx++) + { + avg_rho_re[aarx][aatx*nrOfLayers+atx] = 0; + avg_rho_im[aarx][aatx*nrOfLayers+atx] = 0; + rho128 = (__m128i *)&rho[aarx][aatx*nrOfLayers+atx][symbol*(off+(nb_rb*12))]; + ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[atx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) - mmtmpD1 = _mm_shufflelo_epi16(ul_ch128[0],_MM_SHUFFLE(2,3,0,1)); - mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); - mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate[0]); - // print_ints("im",&mmtmpD1); - mmtmpD1 = _mm_madd_epi16(mmtmpD1,ul_ch128_2[0]); - // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit) - mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); - // print_ints("re(shift)",&mmtmpD0); - mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift); - // print_ints("im(shift)",&mmtmpD1); - mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); - mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); - // print_ints("c0",&mmtmpD2); - // print_ints("c1",&mmtmpD3); - rho128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3); + for (rb=0; rbrx_correlation[0][0][aarx] = signal_energy(&rho[aarx][aatx*nb_aatx+atx][symbol*nb_rb*12],rb*12); + avg_rho_re[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_re[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); + avg_rho_im[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_im[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); + //printf("rho[rx]%d tx%d tx%d = Re: %d Im: %d\n",aarx, aatx,atx, avg_rho_re[aarx][aatx*nb_aatx+atx], avg_rho_im[aarx][aatx*nb_aatx+atx]); + } + } } - } } @@ -1105,19 +1185,23 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, } void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, - int32_t **rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, - uint8_t symbol, - uint16_t nb_rb) { + int32_t **rxdataF_comp, + int32_t **ul_ch_mag, + int32_t **ul_ch_magb, + int32_t ***rho, + uint8_t nrOfLayers, + uint8_t symbol, + uint16_t nb_rb, + int length) { int n_rx = frame_parms->nb_antennas_rx; #if defined(__x86_64__) || defined(__i386__) - __m128i *rxdataF_comp128[1+n_rx],*ul_ch_mag128[1+n_rx],*ul_ch_mag128b[1+n_rx]; + __m128i *rxdataF_comp128[2],*ul_ch_mag128[2],*ul_ch_mag128b[2]; #elif defined(__arm__) int16x8_t *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b; int16x8_t *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b; #endif int32_t i; + uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); #ifdef __AVX2__ int off = ((nb_rb&1) == 1)? 4:0; @@ -1125,23 +1209,34 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, int off = 0; #endif - if (frame_parms->nb_antennas_rx>1) { -#if defined(__x86_64__) || defined(__i386__) - int nb_re = nb_rb*12; - for (int aa=0;aanb_antennas_rx;aa++) { - rxdataF_comp128[aa] = (__m128i *)&rxdataF_comp[aa][(symbol*(nb_re + off))]; - ul_ch_mag128[aa] = (__m128i *)&ul_ch_mag[aa][(symbol*(nb_re + off))]; - ul_ch_mag128b[aa] = (__m128i *)&ul_ch_magb[aa][(symbol*(nb_re + off))]; - } - for (int aa=1;aanb_antennas_rx;aa++) { - // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) - for (i=0; i 1) + { + #if defined(__x86_64__) || defined(__i386__) + for (int aatx=0; aatxnb_antennas_rx][(symbol*(nb_re + off))]; + ul_ch_mag128[0] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; + ul_ch_mag128b[0] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; + + for (int aa=1;aa < n_rx;aa++) + { + rxdataF_comp128[1] = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; + ul_ch_mag128[1] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; + ul_ch_mag128b[1] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; + + // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) + for (i=0; iN_RB_DL*12]; rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12]; ul_ch_mag128_0 = (int16x8_t *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12]; @@ -1156,7 +1251,7 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, ul_ch_mag128_0b[i] = vhaddq_s16(ul_ch_mag128_0b[i],ul_ch_mag128_1b[i]); rxdataF_comp128_0[i] = vqaddq_s16(rxdataF_comp128_0[i],(*(int16x8_t *)&jitterc[0])); } -#endif + #endif } #if defined(__x86_64__) || defined(__i386__) @@ -1165,6 +1260,696 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, #endif } +/* Zero Forcing Rx function: nr_det_HhH() + * + * + * */ +void nr_ulsch_det_HhH(int32_t *after_mf_00,//a + int32_t *after_mf_01,//b + int32_t *after_mf_10,//c + int32_t *after_mf_11,//d + int32_t *det_fin,//1/ad-bc + unsigned short nb_rb, + unsigned char symbol, + int32_t shift) +{ + int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; + unsigned short rb; + __m128i *after_mf_00_128,*after_mf_01_128, *after_mf_10_128, *after_mf_11_128, ad_re_128, bc_re_128; //ad_im_128, bc_im_128; + __m128i *det_fin_128, det_re_128; //det_im_128, tmp_det0, tmp_det1; + + after_mf_00_128 = (__m128i *)after_mf_00; + after_mf_01_128 = (__m128i *)after_mf_01; + after_mf_10_128 = (__m128i *)after_mf_10; + after_mf_11_128 = (__m128i *)after_mf_11; + + det_fin_128 = (__m128i *)det_fin; + + for (rb=0; rb<3*nb_rb; rb++) { + + //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) + //The imag part is often zero, we compute only the real part + ad_re_128 = _mm_sign_epi16(after_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); + ad_re_128 = _mm_madd_epi16(ad_re_128,after_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 + //ad_im_128 = _mm_shufflelo_epi16(after_mf_00_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + //ad_im_128 = _mm_shufflehi_epi16(ad_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + //ad_im_128 = _mm_madd_epi16(ad_im_128,after_mf_11_128[0]);//Im: (Q_aI_d + I_aQ_d) + + //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) + //The imag part is often zero, we compute only the real part + bc_re_128 = _mm_sign_epi16(after_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); + bc_re_128 = _mm_madd_epi16(bc_re_128,after_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 + //bc_im_128 = _mm_shufflelo_epi16(after_mf_01_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits + //bc_im_128 = _mm_shufflehi_epi16(bc_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits + //bc_im_128 = _mm_madd_epi16(bc_im_128,after_mf_10_128[0]);//Im: (Q_bI_c + I_bQ_c) + + det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); + //det_im_128 = _mm_sub_epi32(ad_im_128, bc_im_128); + + //det in Q30 format + det_fin_128[0] = _mm_abs_epi32(det_re_128); + + +#ifdef DEBUG_DLSCH_DEMOD + printf("\n Computing det_HhH_inv \n"); + //print_ints("det_re_128:",(int32_t*)&det_re_128); + //print_ints("det_im_128:",(int32_t*)&det_im_128); + print_ints("det_fin_128:",(int32_t*)&det_fin_128[0]); +#endif + det_fin_128+=1; + after_mf_00_128+=1; + after_mf_01_128+=1; + after_mf_10_128+=1; + after_mf_11_128+=1; + } + _mm_empty(); + _m_empty(); +} + +/* Zero Forcing Rx function: nr_inv_comp_muli + * Complex number multi: z = x*y + * = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) + * */ +__m128i nr_ulsch_inv_comp_muli(__m128i input_x, + __m128i input_y) +{ + int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; + + __m128i xy_re_128, xy_im_128; + __m128i output_z, tmp_z0, tmp_z1; + + // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) + + // the real part + xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); + xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) + + // the imag part + xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) + + //convert back to Q15 before packing + xy_re_128 = _mm_srai_epi32(xy_re_128,4);//(2^15/64*2*16) + xy_im_128 = _mm_srai_epi32(xy_im_128,4); + + tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); + //print_ints("unpack lo:",&tmp_z0[0]); + tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); + //print_ints("unpack hi:",&tmp_z1[0]); + output_z = _mm_packs_epi32(tmp_z0,tmp_z1); + + _mm_empty(); + _m_empty(); + return(output_z); +} + +/* Zero Forcing Rx function: nr_conjch0_mult_ch1() + * + * + * */ +void nr_ulsch_conjch0_mult_ch1(int *ch0, + int *ch1, + int32_t *ch0conj_ch1, + unsigned short nb_rb, + unsigned char output_shift0) +{ + //This function is used to compute multiplications in H_hermitian * H matrix + short nr_conjugate[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1}; + unsigned short rb; + __m128i *dl_ch0_128,*dl_ch1_128, *ch0conj_ch1_128, mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; + + dl_ch0_128 = (__m128i *)ch0; + dl_ch1_128 = (__m128i *)ch1; + + ch0conj_ch1_128 = (__m128i *)ch0conj_ch1; + + for (rb=0; rb<3*nb_rb; rb++) { + + mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0],dl_ch1_128[0]); + mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[0],_MM_SHUFFLE(2,3,0,1)); + mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); + mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&nr_conjugate[0]); + mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch1_128[0]); + mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift0); + mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift0); + mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); + mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); + + ch0conj_ch1_128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3); + + /*printf("\n Computing conjugates \n"); + print_shorts("ch0:",(int16_t*)&dl_ch0_128[0]); + print_shorts("ch1:",(int16_t*)&dl_ch1_128[0]); + print_shorts("pack:",(int16_t*)&ch0conj_ch1_128[0]);*/ + + dl_ch0_128+=1; + dl_ch1_128+=1; + ch0conj_ch1_128+=1; + } + _mm_empty(); + _m_empty(); +} +__m128i nr_ulsch_comp_muli_sum(__m128i input_x, + __m128i input_y, + __m128i input_w, + __m128i input_z, + __m128i det) +{ + int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; + + __m128i xy_re_128, xy_im_128, wz_re_128, wz_im_128; + __m128i output, tmp_z0, tmp_z1; + + // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) + // the real part + xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); + xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) + + // the imag part + xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) + + // complex multiplication (w_re + jw_im)*(z_re + jz_im) = (w_re*z_re - w_im*z_im) + j(w_im*z_re + w_re*z_im) + // the real part + wz_re_128 = _mm_sign_epi16(input_w,*(__m128i*)&nr_conjug2[0]); + wz_re_128 = _mm_madd_epi16(wz_re_128,input_z); //Re: (w_re*z_re - w_im*z_im) + + // the imag part + wz_im_128 = _mm_shufflelo_epi16(input_w,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + wz_im_128 = _mm_shufflehi_epi16(wz_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits + wz_im_128 = _mm_madd_epi16(wz_im_128,input_z);//Im: (w_im*z_re + w_re*z_im) + + + xy_re_128 = _mm_sub_epi32(xy_re_128, wz_re_128); + xy_im_128 = _mm_sub_epi32(xy_im_128, wz_im_128); + //print_ints("rx_re:",(int32_t*)&xy_re_128[0]); + //print_ints("rx_Img:",(int32_t*)&xy_im_128[0]); + //divide by matrix det and convert back to Q15 before packing + int sum_det =0; + for (int k=0; k<4;k++) { + sum_det += ((((int *)&det[0])[k])>>2); + //printf("det_%d = %d log2 =%d \n",k,(((int *)&det[0])[k]),log2_approx(((int *)&det[0])[k])); + } + + xy_re_128 = _mm_slli_epi32(xy_re_128,5); + xy_re_128 = _mm_srai_epi32(xy_re_128,log2_approx(sum_det)); + xy_re_128 = _mm_slli_epi32(xy_re_128,5); + + xy_im_128 = _mm_slli_epi32(xy_im_128,5); + xy_im_128 = _mm_srai_epi32(xy_im_128,log2_approx(sum_det)); + xy_im_128 = _mm_slli_epi32(xy_im_128,5); + + tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); + //print_ints("unpack lo:",&tmp_z0[0]); + tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); + //print_ints("unpack hi:",&tmp_z1[0]); + output = _mm_packs_epi32(tmp_z0,tmp_z1); + + _mm_empty(); + _m_empty(); + return(output); +} +/* Zero Forcing Rx function: nr_construct_HhH_elements() + * + * + * */ +void nr_ulsch_construct_HhH_elements(int *conjch00_ch00, + int *conjch01_ch01, + int *conjch11_ch11, + int *conjch10_ch10,// + int *conjch20_ch20, + int *conjch21_ch21, + int *conjch30_ch30, + int *conjch31_ch31, + int *conjch00_ch01,//00_01 + int *conjch01_ch00,//01_00 + int *conjch10_ch11,//10_11 + int *conjch11_ch10,//11_10 + int *conjch20_ch21, + int *conjch21_ch20, + int *conjch30_ch31, + int *conjch31_ch30, + int32_t *after_mf_00, + int32_t *after_mf_01, + int32_t *after_mf_10, + int32_t *after_mf_11, + unsigned short nb_rb, + unsigned char symbol) +{ + //This function is used to construct the (H_hermitian * H matrix) matrix elements + unsigned short rb; + __m128i *conjch00_ch00_128, *conjch01_ch01_128, *conjch11_ch11_128, *conjch10_ch10_128; + __m128i *conjch20_ch20_128, *conjch21_ch21_128, *conjch30_ch30_128, *conjch31_ch31_128; + __m128i *conjch00_ch01_128, *conjch01_ch00_128, *conjch10_ch11_128, *conjch11_ch10_128; + __m128i *conjch20_ch21_128, *conjch21_ch20_128, *conjch30_ch31_128, *conjch31_ch30_128; + __m128i *after_mf_00_128, *after_mf_01_128, *after_mf_10_128, *after_mf_11_128; + + conjch00_ch00_128 = (__m128i *)conjch00_ch00; + conjch01_ch01_128 = (__m128i *)conjch01_ch01; + conjch11_ch11_128 = (__m128i *)conjch11_ch11; + conjch10_ch10_128 = (__m128i *)conjch10_ch10; + + conjch20_ch20_128 = (__m128i *)conjch20_ch20; + conjch21_ch21_128 = (__m128i *)conjch21_ch21; + conjch30_ch30_128 = (__m128i *)conjch30_ch30; + conjch31_ch31_128 = (__m128i *)conjch31_ch31; + + conjch00_ch01_128 = (__m128i *)conjch00_ch01; + conjch01_ch00_128 = (__m128i *)conjch01_ch00; + conjch10_ch11_128 = (__m128i *)conjch10_ch11; + conjch11_ch10_128 = (__m128i *)conjch11_ch10; + + conjch20_ch21_128 = (__m128i *)conjch20_ch21; + conjch21_ch20_128 = (__m128i *)conjch21_ch20; + conjch30_ch31_128 = (__m128i *)conjch30_ch31; + conjch31_ch30_128 = (__m128i *)conjch31_ch30; + + after_mf_00_128 = (__m128i *)after_mf_00; + after_mf_01_128 = (__m128i *)after_mf_01; + after_mf_10_128 = (__m128i *)after_mf_10; + after_mf_11_128 = (__m128i *)after_mf_11; + + for (rb=0; rb<3*nb_rb; rb++) { + + after_mf_00_128[0] =_mm_adds_epi16(conjch00_ch00_128[0],conjch10_ch10_128[0]);//00_00 + 10_10 + if (conjch20_ch20 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch20_ch20_128[0]); + if (conjch30_ch30 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch30_ch30_128[0]); + + after_mf_11_128[0] =_mm_adds_epi16(conjch01_ch01_128[0], conjch11_ch11_128[0]); //01_01 + 11_11 + if (conjch21_ch21 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch21_ch21_128[0]); + if (conjch31_ch31 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch31_ch31_128[0]); + + after_mf_01_128[0] =_mm_adds_epi16(conjch00_ch01_128[0], conjch10_ch11_128[0]);//00_01 + 10_11 + if (conjch20_ch21 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch20_ch21_128[0]); + if (conjch30_ch31 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch30_ch31_128[0]); + + after_mf_10_128[0] =_mm_adds_epi16(conjch01_ch00_128[0], conjch11_ch10_128[0]);//01_00 + 11_10 + if (conjch21_ch20 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch21_ch20_128[0]); + if (conjch31_ch30 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch31_ch30_128[0]); + +#ifdef DEBUG_DLSCH_DEMOD + if ((rb<=30)) + { + printf(" \n construct_HhH_elements \n"); + print_shorts("after_mf_00_128:",(int16_t*)&after_mf_00_128[0]); + print_shorts("after_mf_01_128:",(int16_t*)&after_mf_01_128[0]); + print_shorts("after_mf_10_128:",(int16_t*)&after_mf_10_128[0]); + print_shorts("after_mf_11_128:",(int16_t*)&after_mf_11_128[0]); + } +#endif + conjch00_ch00_128+=1; + conjch10_ch10_128+=1; + conjch01_ch01_128+=1; + conjch11_ch11_128+=1; + + if (conjch20_ch20 != NULL) conjch20_ch20_128+=1; + if (conjch21_ch21 != NULL) conjch21_ch21_128+=1; + if (conjch30_ch30 != NULL) conjch30_ch30_128+=1; + if (conjch31_ch31 != NULL) conjch31_ch31_128+=1; + + conjch00_ch01_128+=1; + conjch01_ch00_128+=1; + conjch10_ch11_128+=1; + conjch11_ch10_128+=1; + + if (conjch20_ch21 != NULL) conjch20_ch21_128+=1; + if (conjch21_ch20 != NULL) conjch21_ch20_128+=1; + if (conjch30_ch31 != NULL) conjch30_ch31_128+=1; + if (conjch31_ch30 != NULL) conjch31_ch30_128+=1; + + after_mf_00_128 += 1; + after_mf_01_128 += 1; + after_mf_10_128 += 1; + after_mf_11_128 += 1; + } + _mm_empty(); + _m_empty(); +} + +/* Zero Forcing Rx function: nr_ulsch_zero_forcing_rx_2layers() + * + * + * */ +uint8_t nr_ulsch_zero_forcing_rx_2layers(int **rxdataF_comp, + int **ul_ch_mag, + int **ul_ch_magb, + int **ul_ch_estimates_ext, + unsigned short nb_rb, + unsigned char n_rx, + unsigned char mod_order, + int shift, + unsigned char symbol, + int length) +{ + int *ch00, *ch01, *ch10, *ch11; + int *ch20, *ch30, *ch21, *ch31; + uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); + + #ifdef __AVX2__ + int off = ((nb_rb&1) == 1)? 4:0; + #else + int off = 0; + #endif + + /* we need at least alignment to 16 bytes, let's put 32 to be sure + * (maybe not necessary but doesn't hurt) + */ + int32_t conjch00_ch01[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch01_ch00[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch10_ch11[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch11_ch10[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch00_ch00[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch01_ch01[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch10_ch10[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch11_ch11[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch20_ch20[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch21_ch21[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch30_ch30[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch31_ch31[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch20_ch21[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch30_ch31[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch21_ch20[12*nb_rb] __attribute__((aligned(32))); + int32_t conjch31_ch30[12*nb_rb] __attribute__((aligned(32))); + + int32_t af_mf_00[12*nb_rb] __attribute__((aligned(32))); + int32_t af_mf_01[12*nb_rb] __attribute__((aligned(32))); + int32_t af_mf_10[12*nb_rb] __attribute__((aligned(32))); + int32_t af_mf_11[12*nb_rb] __attribute__((aligned(32))); + int32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); + + switch (n_rx) { + case 2:// + ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; + ch01 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; + ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; + ch11 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; + ch20 = NULL; + ch21 = NULL; + ch30 = NULL; + ch31 = NULL; + break; + + case 4:// + ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; + ch01 = (int *)&ul_ch_estimates_ext[4][symbol*(off+nb_rb*12)]; + ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; + ch11 = (int *)&ul_ch_estimates_ext[5][symbol*(off+nb_rb*12)]; + ch20 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; + ch21 = (int *)&ul_ch_estimates_ext[6][symbol*(off+nb_rb*12)]; + ch30 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; + ch31 = (int *)&ul_ch_estimates_ext[7][symbol*(off+nb_rb*12)]; + break; + + default: + return -1; + break; + } + + /* 1- Compute the rx channel matrix after compensation: (1/2^log2_max)x(H_herm x H) + * for n_rx = 2 + * |conj_H_00 conj_H_10| | H_00 H_01| |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| + * | | x | | = | | + * |conj_H_01 conj_H_11| | H_10 H_11| |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| + * + */ + + if (n_rx>=2){ + // (1/2^log2_maxh)*conj_H_00xH_00: (1/(64*2))conjH_00*H_00*2^15 + nr_ulsch_conjch0_mult_ch1(ch00, + ch00, + conjch00_ch00, + nb_rb_0, + shift); + // (1/2^log2_maxh)*conj_H_10xH_10: (1/(64*2))conjH_10*H_10*2^15 + nr_ulsch_conjch0_mult_ch1(ch10, + ch10, + conjch10_ch10, + nb_rb_0, + shift); + // conj_H_00xH_01 + nr_ulsch_conjch0_mult_ch1(ch00, + ch01, + conjch00_ch01, + nb_rb_0, + shift); // this shift is equal to the channel level log2_maxh + // conj_H_10xH_11 + nr_ulsch_conjch0_mult_ch1(ch10, + ch11, + conjch10_ch11, + nb_rb_0, + shift); + // conj_H_01xH_01 + nr_ulsch_conjch0_mult_ch1(ch01, + ch01, + conjch01_ch01, + nb_rb_0, + shift); + // conj_H_11xH_11 + nr_ulsch_conjch0_mult_ch1(ch11, + ch11, + conjch11_ch11, + nb_rb_0, + shift); + // conj_H_01xH_00 + nr_ulsch_conjch0_mult_ch1(ch01, + ch00, + conjch01_ch00, + nb_rb_0, + shift); + // conj_H_11xH_10 + nr_ulsch_conjch0_mult_ch1(ch11, + ch10, + conjch11_ch10, + nb_rb_0, + shift); + } + if (n_rx==4){ + // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2*16))conjH_20*H_20*2^15 + nr_ulsch_conjch0_mult_ch1(ch20, + ch20, + conjch20_ch20, + nb_rb_0, + shift); + + // (1/2^log2_maxh)*conj_H_30xH_30: (1/(64*2*4))conjH_30*H_30*2^15 + nr_ulsch_conjch0_mult_ch1(ch30, + ch30, + conjch30_ch30, + nb_rb_0, + shift); + + // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 + nr_ulsch_conjch0_mult_ch1(ch20, + ch21, + conjch20_ch21, + nb_rb_0, + shift); + + nr_ulsch_conjch0_mult_ch1(ch30, + ch31, + conjch30_ch31, + nb_rb_0, + shift); + + nr_ulsch_conjch0_mult_ch1(ch21, + ch21, + conjch21_ch21, + nb_rb_0, + shift); + + nr_ulsch_conjch0_mult_ch1(ch31, + ch31, + conjch31_ch31, + nb_rb_0, + shift); + + // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 + nr_ulsch_conjch0_mult_ch1(ch21, + ch20, + conjch21_ch20, + nb_rb_0, + shift); + + nr_ulsch_conjch0_mult_ch1(ch31, + ch30, + conjch31_ch30, + nb_rb_0, + shift); + + nr_ulsch_construct_HhH_elements(conjch00_ch00, + conjch01_ch01, + conjch11_ch11, + conjch10_ch10,// + conjch20_ch20, + conjch21_ch21, + conjch30_ch30, + conjch31_ch31, + conjch00_ch01, + conjch01_ch00, + conjch10_ch11, + conjch11_ch10,// + conjch20_ch21, + conjch21_ch20, + conjch30_ch31, + conjch31_ch30, + af_mf_00, + af_mf_01, + af_mf_10, + af_mf_11, + nb_rb_0, + symbol); + } + if (n_rx==2){ + nr_ulsch_construct_HhH_elements(conjch00_ch00, + conjch01_ch01, + conjch11_ch11, + conjch10_ch10,// + NULL, + NULL, + NULL, + NULL, + conjch00_ch01, + conjch01_ch00, + conjch10_ch11, + conjch11_ch10,// + NULL, + NULL, + NULL, + NULL, + af_mf_00, + af_mf_01, + af_mf_10, + af_mf_11, + nb_rb_0, + symbol); + } + //det_HhH = ad -bc + nr_ulsch_det_HhH(af_mf_00,//a + af_mf_01,//b + af_mf_10,//c + af_mf_11,//d + determ_fin, + nb_rb_0, + symbol, + shift); + /* 2- Compute the channel matrix inversion ********************************** + * + * |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| + * A= | | + * |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| + * + * + * + *inv(A) =(1/det)*[d -b + * -c a] + * + * + **************************************************************************/ + __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*ul_ch_mag128_0=NULL,*ul_ch_mag128b_0=NULL,*determ_fin_128;//*dl_ch_mag128_1,*dl_ch_mag128b_1,*dl_ch_mag128r_1 + __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; + __m128i *after_mf_a_128,*after_mf_b_128, *after_mf_c_128, *after_mf_d_128; + __m128i QAM_amp128={0},QAM_amp128b={0}; + + determ_fin_128 = (__m128i *)&determ_fin[0]; + + rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[0][symbol*(off+nb_rb*12)];//aatx=0 @ aarx =0 + rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[n_rx][symbol*(off+nb_rb*12)];//aatx=1 @ aarx =0 + + after_mf_a_128 = (__m128i *)af_mf_00; + after_mf_b_128 = (__m128i *)af_mf_01; + after_mf_c_128 = (__m128i *)af_mf_10; + after_mf_d_128 = (__m128i *)af_mf_11; + + if (mod_order>2) { + if (mod_order == 4) { + QAM_amp128 = _mm_set1_epi16(QAM16_n1); //2/sqrt(10) + QAM_amp128b = _mm_setzero_si128(); + } else if (mod_order == 6) { + QAM_amp128 = _mm_set1_epi16(QAM64_n1); //4/sqrt{42} + QAM_amp128b = _mm_set1_epi16(QAM64_n2); //2/sqrt{42} + } + ul_ch_mag128_0 = (__m128i *)&ul_ch_mag[0][symbol*(off+nb_rb*12)]; + ul_ch_mag128b_0 = (__m128i *)&ul_ch_magb[0][symbol*(off+nb_rb*12)]; + } + + for (int rb=0; rb<3*nb_rb_0; rb++) { + if (mod_order>2) { + int sum_det =0; + for (int k=0; k<4;k++) { + sum_det += ((((int *)&determ_fin_128[0])[k])>>2); + //printf("det_%d = %d\n",k,sum_det); + } + + mmtmpD2 = _mm_slli_epi32(determ_fin_128[0],5); + mmtmpD2 = _mm_srai_epi32(mmtmpD2,log2_approx(sum_det)); + mmtmpD2 = _mm_slli_epi32(mmtmpD2,5); + + mmtmpD3 = _mm_unpacklo_epi32(mmtmpD2,mmtmpD2); + + mmtmpD2 = _mm_unpackhi_epi32(mmtmpD2,mmtmpD2); + + mmtmpD2 = _mm_packs_epi32(mmtmpD3,mmtmpD2); + + ul_ch_mag128_0[0] = mmtmpD2; + ul_ch_mag128b_0[0] = mmtmpD2; + + ul_ch_mag128_0[0] = _mm_mulhi_epi16(ul_ch_mag128_0[0],QAM_amp128); + ul_ch_mag128_0[0] = _mm_slli_epi16(ul_ch_mag128_0[0],1); + + ul_ch_mag128b_0[0] = _mm_mulhi_epi16(ul_ch_mag128b_0[0],QAM_amp128b); + ul_ch_mag128b_0[0] = _mm_slli_epi16(ul_ch_mag128b_0[0],1); + + //print_shorts("mag layer 1:",(int16_t*)&dl_ch_mag128_0[0]); + //print_shorts("mag layer 2:",(int16_t*)&dl_ch_mag128_1[0]); + //print_shorts("magb layer 1:",(int16_t*)&dl_ch_mag128b_0[0]); + //print_shorts("magb layer 2:",(int16_t*)&dl_ch_mag128b_1[0]); + //print_shorts("magr layer 1:",(int16_t*)&dl_ch_mag128r_0[0]); + //print_shorts("magr layer 2:",(int16_t*)&dl_ch_mag128r_1[0]); + } + // multiply by channel Inv + //rxdataF_zf128_0 = rxdataF_comp128_0*d - b*rxdataF_comp128_1 + //rxdataF_zf128_1 = rxdataF_comp128_1*a - c*rxdataF_comp128_0 + //printf("layer_1 \n"); + mmtmpD0 = nr_ulsch_comp_muli_sum(rxdataF_comp128_0[0], + after_mf_d_128[0], + rxdataF_comp128_1[0], + after_mf_b_128[0], + determ_fin_128[0]); + + //printf("layer_2 \n"); + mmtmpD1 = nr_ulsch_comp_muli_sum(rxdataF_comp128_1[0], + after_mf_a_128[0], + rxdataF_comp128_0[0], + after_mf_c_128[0], + determ_fin_128[0]); + + rxdataF_comp128_0[0] = mmtmpD0; + rxdataF_comp128_1[0] = mmtmpD1; +#ifdef DEBUG_DLSCH_DEMOD + printf("\n Rx signal after ZF l%d rb%d\n",symbol,rb); + print_shorts(" Rx layer 1:",(int16_t*)&rxdataF_comp128_0[0]); + print_shorts(" Rx layer 2:",(int16_t*)&rxdataF_comp128_1[0]); +#endif + determ_fin_128 += 1; + ul_ch_mag128_0 += 1; + ul_ch_mag128b_0 += 1; + rxdataF_comp128_0 += 1; + rxdataF_comp128_1 += 1; + after_mf_a_128 += 1; + after_mf_b_128 += 1; + after_mf_c_128 += 1; + after_mf_d_128 += 1; + } + _mm_empty(); + _m_empty(); + return(0); +} + +//============================================================================================== + +/* Main Function */ int nr_rx_pusch(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, @@ -1184,21 +1969,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->cl_done = 0; bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start)*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; - LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); - LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); - + LOG_I(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); + LOG_I(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); + LOG_I(PHY,"ulsch RX %x : start_rb %d nb_rb %d mcs %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_ports %d\n", + rel15_ul->rnti,rel15_ul->rb_start,rel15_ul->rb_size,rel15_ul->mcs_index, + rel15_ul->nrOfLayers,0,rel15_ul->bwp_start,0,rel15_ul->start_symbol_index,rel15_ul->nr_of_symbols, + rel15_ul->num_dmrs_cdm_grps_no_data,rel15_ul->ul_dmrs_symb_pos,rel15_ul->dmrs_ports); //---------------------------------------------------------- //--------------------- Channel estimation --------------------- //---------------------------------------------------------- start_meas(&gNB->ulsch_channel_estimation_stats); - for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) + { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag); - if (dmrs_symbol_flag == 1) { + + if (dmrs_symbol_flag == 1) + { if (gNB->pusch_vars[ulsch_id]->dmrs_symbol == INVALID_VALUE) gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; for (int nl=0; nlnrOfLayers; nl++) + { + nr_pusch_channel_estimation(gNB, slot, get_dmrs_port(nl,rel15_ul->dmrs_ports), @@ -1206,6 +1999,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, ulsch_id, bwp_start_subcarrier, rel15_ul); + } nr_gnb_measurements(gNB, ulsch_id, harq_pid, symbol,rel15_ul->nrOfLayers); @@ -1214,9 +2008,12 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] = 0; gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] = 0; } - gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( - &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aarx][symbol * frame_parms->ofdm_symbol_size], + for (aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) + { + gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( + &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aatx*gNB->frame_parms.nb_antennas_rx+aarx][symbol * frame_parms->ofdm_symbol_size], rel15_ul->rb_size * 12); + } for (int rb = 0; rb < rel15_ul->rb_size; rb++) { gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] += gNB->measurements.n0_subband_power[aarx][rel15_ul->bwp_start + rel15_ul->rb_start + rb] / @@ -1234,23 +2031,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, #endif uint32_t rxdataF_ext_offset = 0; - for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) + { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; - if (dmrs_symbol_flag == 1) { + if (dmrs_symbol_flag == 1) + { if ((rel15_ul->ul_dmrs_symb_pos >> ((symbol + 1) % frame_parms->symbols_per_slot)) & 0x01) AssertFatal(1==0,"Double DMRS configuration is not yet supported\n"); gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; - if (rel15_ul->dmrs_config_type == 0) { + if (rel15_ul->dmrs_config_type == 0) + { // if no data in dmrs cdm group is 1 only even REs have no data // if no data in dmrs cdm group is 2 both odd and even REs have no data nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*6)); } - else { + else + { nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*4)); } - } else { + } + else + { nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; } @@ -1260,16 +2063,16 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, //---------------------------------------------------------- //--------------------- RBs extraction --------------------- //---------------------------------------------------------- - if (nb_re_pusch > 0) { - + if (nb_re_pusch > 0) + { start_meas(&gNB->ulsch_rbs_extraction_stats); - nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF, - gNB->pusch_vars[ulsch_id], - slot, - symbol, - dmrs_symbol_flag, - rel15_ul, - frame_parms); + nr_ulsch_extract_rbs(gNB->common_vars.rxdataF, + gNB->pusch_vars[ulsch_id], + slot, + symbol, + dmrs_symbol_flag, + rel15_ul, + frame_parms); stop_meas(&gNB->ulsch_rbs_extraction_stats); //---------------------------------------------------------- @@ -1280,8 +2083,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->ulsch[ulsch_id], symbol, dmrs_symbol_flag, - rel15_ul->rb_size, - rel15_ul->dmrs_config_type); + nb_re_pusch, + rel15_ul->nrOfLayers, + rel15_ul->rb_size); if (gNB->pusch_vars[ulsch_id]->cl_done==0) { nr_ulsch_channel_level(gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, @@ -1312,9 +2116,14 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->ul_ch_mag0, gNB->pusch_vars[ulsch_id]->ul_ch_magb0, gNB->pusch_vars[ulsch_id]->rxdataF_comp, + #ifdef SUPPORT_PMI_MATRIC (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, + #else + NULL, + #endif frame_parms, symbol, + nb_re_pusch, dmrs_symbol_flag, rel15_ul->qam_mod_order, rel15_ul->nrOfLayers, @@ -1327,19 +2136,37 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->rxdataF_comp, gNB->pusch_vars[ulsch_id]->ul_ch_mag0, gNB->pusch_vars[ulsch_id]->ul_ch_magb0, + #ifdef SUPPORT_PMI_MATRIC + (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, + #else + NULL, + #endif + rel15_ul->nrOfLayers, symbol, - rel15_ul->rb_size); + rel15_ul->rb_size, + nb_re_pusch); + + if (rel15_ul->nrOfLayers == 2)//Apply zero forcing for 2 Tx layers + nr_ulsch_zero_forcing_rx_2layers(gNB->pusch_vars[ulsch_id]->rxdataF_comp, + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, + gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, + rel15_ul->rb_size, + frame_parms->nb_antennas_rx, + rel15_ul->qam_mod_order, + gNB->pusch_vars[ulsch_id]->log2_maxh, + symbol, + nb_re_pusch); stop_meas(&gNB->ulsch_mrc_stats); - // transform precoding = 0 means enabled - if (rel15_ul->transform_precoding == 0) { - - #ifdef __AVX2__ + if (rel15_ul->transformPrecoder == transformPrecoder_enabled) + { + #ifdef __AVX2__ // For odd number of resource blocks need byte alignment to multiple of 8 int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); - #else + #else int nb_re_pusch2 = nb_re_pusch; - #endif + #endif // perform IDFT operation on the compensated rxdata if transform precoding is enabled nr_idft(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * nb_re_pusch2], nb_re_pusch); @@ -1351,7 +2178,8 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, //---------------------------------------------------------- /* In case PTRS is enabled then LLR will be calculated after PTRS symbols are processed * * otherwise LLR are calculated for each symbol based upon DMRS channel estimates only. */ - if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) + { start_meas(&gNB->ulsch_ptrs_processing_stats); nr_pusch_ptrs_processing(gNB, frame_parms, @@ -1370,14 +2198,17 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, /*-------------------- LLRs computation -------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------*/ start_meas(&gNB->ulsch_llr_stats); - nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], - gNB->pusch_vars[ulsch_id]->ul_ch_mag0, - gNB->pusch_vars[ulsch_id]->ul_ch_magb0, - &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order], - rel15_ul->rb_size, - gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], - symbol, - rel15_ul->qam_mod_order); + for (aatx=0; aatx < rel15_ul->nrOfLayers; aatx++) + { + nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aatx*frame_parms->nb_antennas_rx][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], + gNB->pusch_vars[ulsch_id]->ul_ch_mag0[aatx*frame_parms->nb_antennas_rx], + gNB->pusch_vars[ulsch_id]->ul_ch_magb0[aatx*frame_parms->nb_antennas_rx], + &gNB->pusch_vars[ulsch_id]->llr_layers[aatx][rxdataF_ext_offset * rel15_ul->qam_mod_order], + rel15_ul->rb_size, + gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], + symbol, + rel15_ul->qam_mod_order); + } stop_meas(&gNB->ulsch_llr_stats); rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol]; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index bf96a76106..ad41ebf3d6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -64,7 +64,7 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, //---------------------------------------------------------------------------------------------- void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, + int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_rb, uint32_t nb_re, @@ -110,12 +110,12 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, #if defined(__x86_64__) || defined(__i386__) #ifdef __AVX2__ - ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; + ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; #else - ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; + ch_mag = (__m128i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; #endif #elif defined(__arm__) - ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; + ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; #endif #ifdef __AVX2__ @@ -231,8 +231,8 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, //---------------------------------------------------------------------------------------------- void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, int16_t *ulsch_llr, uint32_t nb_rb, uint32_t nb_re, @@ -265,15 +265,15 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, #if defined(__x86_64__) || defined(__i386__) #ifdef __AVX2__ - ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; - ch_magb = (__m256i*)&ul_ch_magb[0][(symbol*(off+(nb_rb*12)))]; + ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; + ch_magb = (__m256i*)&ul_ch_magb[(symbol*(off+(nb_rb*12)))]; #else - ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)]; - ch_magb = (__m128i*)&ul_ch_magb[0][(symbol*nb_rb*12)]; + ch_mag = (__m128i*)&ul_ch_mag[(symbol*nb_rb*12)]; + ch_magb = (__m128i*)&ul_ch_magb[(symbol*nb_rb*12)]; #endif #elif defined(__arm__) - ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; - ch_magb = (int16x8_t*)&ul_ch_magb[0][(symbol*nb_rb*12)]; + ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; + ch_magb = (int16x8_t*)&ul_ch_magb[(symbol*nb_rb*12)]; #endif #ifdef __AVX2__ @@ -471,8 +471,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, void nr_ulsch_compute_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, int16_t *ulsch_llr, uint32_t nb_rb, uint32_t nb_re, diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c index 65ae288252..2cb7609d62 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c +++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c @@ -148,7 +148,7 @@ short filt8_dcr0_h[8]= { 0,4096,8192,12288,16384,0,0,0}; short filt8_l1[8] = { -24576,16384,0,0,0,0,0,0}; +24576,16384,8192,0,0,0,0,0}; short filt8_ml1[8] = { -8192,0,8192,16384,8192,0,0,0}; @@ -163,10 +163,10 @@ short filt8_mm1[8]= { 0,0,0,0,8192,16384,8192,0}; short filt8_dcl1[8]= { -0,0,0,16384,12288,8192,4096,0}; +0,0,16384,12288,8192,4096,0,0}; short filt8_dcr1[8]= { -0,0,0,0,4096,8192,12288,16384}; +0,0,0,4096,8192,12288,16384,0}; short filt8_dcl1_h[8]= { 0,16384,12288,8192,4096,0,0,0}; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 945dc51673..a293eec6d8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -258,6 +258,15 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, Ilbrm = 0; Tbslbrm = 950984; //max tbs Coderate = 0.0; + + #if 0 + harq_process->a[0] = 0x31; + for (int i = 1; i < harq_process->pusch_pdu.pusch_data.tb_size; i++) + { + harq_process->a[i] = (i&0xff); + } + #endif + trace_NRpdu(DIRECTION_UPLINK, harq_process->a, harq_process->pusch_pdu.pusch_data.tb_size, 0, WS_C_RNTI, 0, 0, 0,0, 0); /////////// ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 99dc2b658e..5d76e654ba 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -98,13 +98,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t thread_id, int gNB_id) { - LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); + LOG_I(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); uint32_t available_bits; uint8_t cwd_index, l; uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; - int16_t **tx_layers; - int32_t **txdataF; + int8_t Wf[2], Wt[2], l_prime[2], delta; uint8_t nb_dmrs_re_per_rb; int ap, i; @@ -112,6 +111,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id]; + int16_t **tx_layers = (int16_t **)pusch_ue->txdataF_layers; + int16_t **tx_precoding = (int16_t **)pusch_ue->txdataF_precoding; + int32_t **txdataF = UE->common_vars.txdataF; uint8_t num_of_codewords = 1; // tmp assumption int Nid_cell = 0; @@ -148,9 +150,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; - LOG_D(PHY,"ulsch %x : start_rb %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", - rnti,start_rb,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); - + LOG_I(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", + rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); + // TbD num_of_mod_symbols is set but never used N_RE_prime = NR_NB_SC_PER_RB*number_of_symbols - nb_dmrs_re_per_rb*number_dmrs_symbols - N_PRB_oh; harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb*num_of_codewords; @@ -236,8 +238,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH layer mapping///////////////////////// /////////// - tx_layers = (int16_t **)pusch_ue->txdataF_layers; - nr_ue_layer_mapping(UE->ulsch[thread_id][gNB_id], Nl, available_bits/mod_order, @@ -257,7 +257,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, int16_t *dmrs_seq = NULL; // if transform precoding is enbaled (value 0) - if (pusch_pdu->transform_precoding == 0) { + if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; uint32_t y_offset = 0; @@ -315,10 +315,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); #endif - } - else - memcpy(ulsch_ue->y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); - + } /////////// //////////////////////////////////////////////////////////////////////// @@ -328,145 +325,233 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH RE mapping///////////////////////// /////////// - txdataF = UE->common_vars.txdataF; - - for (ap=0; ap< Nl; ap++) { - - uint8_t k_prime = 0; - uint16_t m = 0; - - - #ifdef DEBUG_PUSCH_MAPPING + for (ap=0; ap< Nl; ap++) + { + uint8_t k_prime = 0; + uint16_t m = 0; + + #ifdef DEBUG_PUSCH_MAPPING printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); - #endif + #endif - + // DMRS params for this ap + get_Wt(Wt, ap, dmrs_type); + get_Wf(Wf, ap, dmrs_type); + delta = get_delta(ap, dmrs_type); - // DMRS params for this ap - get_Wt(Wt, ap, dmrs_type); - get_Wf(Wf, ap, dmrs_type); - delta = get_delta(ap, dmrs_type); + for (l=start_symbol; l> l) & 0x01) + { + is_dmrs_sym = 1; + if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) + { + if (dmrs_type == pusch_dmrs_type1) + dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; + else + dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; - uint16_t k = start_sc; - uint16_t n = 0; - uint8_t is_dmrs_sym = 0; - uint8_t is_ptrs_sym = 0; - uint16_t dmrs_idx = 0, ptrs_idx = 0; + // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part + // Perform this on gold sequence, not required when SC FDMA operation is done, + LOG_D(PHY,"DMRS in symbol %d\n",l); + nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated + } + else + { + dmrs_idx = 0; + } + } + else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) + { + AssertFatal(pusch_pdu->transformPrecoder == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); - if ((ul_dmrs_symb_pos >> l) & 0x01) { - is_dmrs_sym = 1; - - // transform precoding disabled (value 1) - if (pusch_pdu->transform_precoding == 1){ - - if (dmrs_type == pusch_dmrs_type1) - dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; - else - dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; - - // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part - // Perform this on gold sequence, not required when SC FDMA operation is done, - LOG_D(PHY,"DMRS in symbol %d\n",l); - nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated - - } else { - dmrs_idx = 0; + if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) + { + is_ptrs_sym = 1; + nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); + } } - - - } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - AssertFatal(pusch_pdu->transform_precoding == 1, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); + for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) + { + uint8_t is_dmrs = 0; + uint8_t is_ptrs = 0; - if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { - is_ptrs_sym = 1; - nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); - } - } + sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) { - - uint8_t is_dmrs = 0; - uint8_t is_ptrs = 0; - - sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - - if (is_dmrs_sym) { - if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) - is_dmrs = 1; - } else if (is_ptrs_sym) { + if (is_dmrs_sym) + { + if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) + is_dmrs = 1; + } + else if (is_ptrs_sym) + { is_ptrs = is_ptrs_subcarrier(k, - rnti, - ap, - dmrs_type, - K_ptrs, - nb_rb, - pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, - start_sc, - frame_parms->ofdm_symbol_size); - } + rnti, + ap, + dmrs_type, + K_ptrs, + nb_rb, + pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, + start_sc, + frame_parms->ofdm_symbol_size); + } - if (is_dmrs == 1) { - // if transform precoding is enabled - if (pusch_pdu->transform_precoding == 0) { + if (is_dmrs == 1) + { + if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; + } + else + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; + } + + #ifdef DEBUG_PUSCH_MAPPING + printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", + ap, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); + #endif + + dmrs_idx++; + k_prime++; + k_prime&=1; + n+=(k_prime)?0:1; + } + else if (is_ptrs == 1) + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; + + ptrs_idx++; + } + else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) + { + if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[ap])[m<<1]; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[ap])[(m<<1) + 1]; + } + else + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; + } + + #ifdef DEBUG_PUSCH_MAPPING + printf("DATA: layer %d\t m %d\t l %d \t k %d \t txdataF: %d %d\n", + ap, m, l, k, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); + #endif + + m++; + } + else + { + ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = 0; + ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = 0; + } + + if (++k >= frame_parms->ofdm_symbol_size) + { + k -= frame_parms->ofdm_symbol_size; + } + } //for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) + }//for (l=start_symbol; lnb_antennas_tx; ap++) + { + for (int l=start_symbol; lTpmi; - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; - - } else { - - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; - + if (pmi == 0) {//unitary Precoding + if(ap< pusch_pdu->nrOfLayers) + memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], + (void*)&tx_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)], + NR_NB_SC_PER_RB*sizeof(int32_t)); + else + memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], + 0, + NR_NB_SC_PER_RB*sizeof(int32_t)); + + k += NR_NB_SC_PER_RB; + if (k >= frame_parms->ofdm_symbol_size) { + k -= frame_parms->ofdm_symbol_size; + } + } + else + { + //get the precoding matrix weights: + char *W_prec; + switch (frame_parms->nb_antennas_tx) + { + case 1://1 antenna port + W_prec = nr_W_1l_2p[pmi][ap]; + break; + case 2://2 antenna ports + if (pusch_pdu->nrOfLayers == 1)//1 layer + W_prec = nr_W_1l_2p[pmi][ap]; + else//2 layers + W_prec = nr_W_2l_2p[pmi][ap]; + break; + case 4://4 antenna ports + if (pusch_pdu->nrOfLayers == 1)//1 layer + W_prec = nr_W_1l_4p[pmi][ap]; + else if (pusch_pdu->nrOfLayers == 2)//2 layers + W_prec = nr_W_2l_4p[pmi][ap]; + else if (pusch_pdu->nrOfLayers == 3)//3 layers + W_prec = nr_W_3l_4p[pmi][ap]; + else//4 layers + W_prec = nr_W_4l_4p[pmi][ap]; + break; + default: + LOG_D(PHY,"Precoding 1,2, or 4 antenna ports are currently supported\n"); + W_prec = nr_W_1l_2p[pmi][ap]; + break; } - #ifdef DEBUG_PUSCH_MAPPING - printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", - dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); - #endif + for (int i=0; iofdm_symbol_size + k; + int32_t precodatatx_F = nr_layer_precoder(tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); + ((int16_t*)txdataF[ap])[(re_offset<<1)] = ((int16_t *) &precodatatx_F)[0]; + ((int16_t*)txdataF[ap])[(re_offset<<1) + 1] = ((int16_t *) &precodatatx_F)[1]; + + if (++k >= frame_parms->ofdm_symbol_size) + { + k -= frame_parms->ofdm_symbol_size; + } + } + } + } //RB loop + } // symbol loop + }// port loop - - dmrs_idx++; - k_prime++; - k_prime&=1; - n+=(k_prime)?0:1; - - } else if (is_ptrs == 1) { - - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; - - ptrs_idx++; - - } else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { - - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; - - #ifdef DEBUG_PUSCH_MAPPING - printf("m %d\t l %d \t k %d \t txdataF: %d %d\n", - m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); - #endif - - m++; - - } else { - - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = 0; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = 0; - - } - - if (++k >= frame_parms->ofdm_symbol_size) - k -= frame_parms->ofdm_symbol_size; - } - } - } - } + } //for (cwd_index = 0;cwd_index < num_of_codewords; cwd_index++) NR_UL_UE_HARQ_t *harq_process_ulsch=NULL; harq_process_ulsch = UE->ulsch[thread_id][gNB_id][0]->harq_processes[harq_pid]; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 11b5112a6c..600ba07cb3 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -479,7 +479,7 @@ typedef struct { /// \brief Cross-correlation of two UE signals. /// - first index: rx antenna [0..nb_antennas_rx[ /// - second index: symbol [0..] - int32_t **rho; + int32_t ***rho; /// \f$\log_2(\max|H_i|^2)\f$ int16_t log2_maxh; /// \brief Magnitude of Uplink Channel first layer (16QAM level/First 64QAM level). @@ -509,6 +509,10 @@ typedef struct { /// \brief llr values. /// - first index: ? [0..1179743] (hard coded) int16_t *llr; + /// \brief llr values per layer. + /// - first index: ? [0..3] (hard coded) + /// - first index: ? [0..1179743] (hard coded) + int16_t **llr_layers; /// DMRS symbol index, to be updated every DMRS symbol within a slot. uint8_t dmrs_symbol; // PTRS symbol index, to be updated every PTRS symbol within a slot. diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 69978f5548..02988b590a 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -229,6 +229,9 @@ typedef struct { typedef struct { /// TX buffers for multiple layers int32_t *txdataF_layers[NR_MAX_NB_LAYERS]; + + /// TX buffers for UE-spec transmission + int32_t *txdataF_precoding[NR_MAX_NB_LAYERS]; } NR_UE_PUSCH; typedef struct { diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index c385d323e3..fbe094f41c 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -93,7 +93,7 @@ #define NR_MAX_CSET_DURATION 3 #define NR_MAX_NB_RBG 18 -#define NR_MAX_NB_LAYERS 2 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) +#define NR_MAX_NB_LAYERS 4 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) #define NR_MAX_NB_CODEWORDS 2 #define NR_MAX_NB_HARQ_PROCESSES 16 #define NR_MAX_PDSCH_ENCODED_LENGTH (NR_MAX_NB_RB*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8*NR_MAX_NB_LAYERS) // 8 is the maximum modulation order (it was 950984 before !!) @@ -104,11 +104,11 @@ #define MAX_NUM_NR_DLSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) #define MAX_NR_DLSCH_PAYLOAD_BYTES (MAX_NUM_NR_DLSCH_SEGMENTS*1056) -#define MAX_NUM_NR_ULSCH_SEGMENTS 34 +#define MAX_NUM_NR_ULSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) #define MAX_NR_ULSCH_PAYLOAD_BYTES (MAX_NUM_NR_ULSCH_SEGMENTS*1056) -#define MAX_NUM_NR_CHANNEL_BITS (14*273*12*8) // 14 symbols, 273 RB -#define MAX_NUM_NR_RE (14*273*12) +#define MAX_NUM_NR_CHANNEL_BITS (4*14*273*12*8) // 14 symbols, 273 RB +#define MAX_NUM_NR_RE (4*14*273*12) #define NR_RX_NB_TH 1 #define NR_NB_TH_SLOT 2 diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index d8fa11d157..640a0740ef 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -526,7 +526,8 @@ void nr_fep0(RU_t *ru, int first_half) { end_symbol = NR_SYMBOLS_PER_SLOT; } - LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d\n", proc->tti_rx, first_half, start_symbol, end_symbol); + LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d, nb_antennas_rx = %d,N_TA_offset = %d\n", + proc->tti_rx, first_half, start_symbol, end_symbol,fp->nb_antennas_rx,ru->N_TA_offset); // printf("fep0: slot %d\n",slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 1); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1685e206ae..63c708e565 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -253,13 +253,13 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { // if all segments are done if (rdata->nbSegments == ulsch_harq->processedSegments) { if (decodeSuccess) { - LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", + LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); ulsch_harq->status = SCH_IDLE; ulsch_harq->round = 0; ulsch->harq_mask &= ~(1 << rdata->harq_pid); - LOG_D(PHY, "ULSCH received ok \n"); + LOG_I(PHY, "ULSCH received ok \n"); nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); //dumpsig=1; } else { @@ -281,7 +281,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { } ulsch_harq->handled = 1; - LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); + LOG_I(PHY, "ULSCH %d in error\n",rdata->ulsch_id); nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1,0); } /* @@ -365,6 +365,14 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs pusch_pdu->qam_mod_order, pusch_pdu->nrOfLayers); + + + nr_ulsch_layer_demapping(gNB->pusch_vars[ULSCH_id]->llr, + pusch_pdu->nrOfLayers, + pusch_pdu->qam_mod_order, + G, + gNB->pusch_vars[ULSCH_id]->llr_layers); + //---------------------------------------------------------- //------------------- ULSCH unscrambling ------------------- //---------------------------------------------------------- @@ -731,7 +739,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { (ulsch_harq->slot == slot_rx) && (ulsch_harq->handled == 0)){ - LOG_D(PHY, "PUSCH detection started in frame %d slot %d\n", + LOG_I(PHY, "PUSCH detection started in frame %d slot %d\n", frame_rx,slot_rx); int num_dmrs=0; for (int s=0;srx_pusch_stats); no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); if (no_sig) { - LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); + LOG_I(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); return 1; } @@ -783,7 +791,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot) + gNB->pusch_thres) { NR_gNB_SCH_STATS_t *stats=get_ulsch_stats(gNB,ulsch); - LOG_D(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, + LOG_I(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot), dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres); gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot; diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index f6e4d90bee..8e1df435c3 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -157,7 +157,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ for (i = 0; i < ul_config->number_pdus; ++i){ AssertFatal(ul_config->ul_config_list[i].pdu_type <= FAPI_NR_UL_CONFIG_TYPES,"pdu_type %d out of bounds\n",ul_config->ul_config_list[i].pdu_type); - LOG_D(PHY, "In %s: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); + LOG_I(PHY, "In %s i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type, current_harq_pid, gNB_id = 0; /* PRACH */ @@ -180,6 +180,8 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ if (harq_process_ul_ue){ nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &harq_process_ul_ue->pusch_pdu; + + LOG_I(PHY, "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n", __FUNCTION__, i, pusch_config_pdu->nrOfLayers,pusch_config_pdu->num_dmrs_cdm_grps_no_data); memcpy(pusch_pdu, pusch_config_pdu, sizeof(nfapi_nr_ue_pusch_pdu_t)); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 940931694c..0a0a9cc2f9 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -270,9 +270,12 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN); - - memset(ue->common_vars.txdataF[0], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); - + + for(int i=0; i< ue->frame_parms.nb_antennas_tx; ++i) + { + memset(ue->common_vars.txdataF[i], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); + } + LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 1eb6027936..d5a1054654 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -768,7 +768,7 @@ int main(int argc, char **argv) prepare_scd(scd); - fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); + fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); /* RRC parameter validation for secondaryCellGroup */ fix_scd(scd); diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index 94aea36a67..fb8b4295ae 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -137,6 +137,7 @@ int main(int argc, char **argv) uint16_t nb_symb_sch = 12; uint16_t nb_rb = 50; uint8_t Imcs = 9; + uint8_t Nl = 1; double DS_TDL = .03; @@ -150,7 +151,7 @@ int main(int argc, char **argv) randominit(0); //while ((c = getopt(argc, argv, "df:hpg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:")) != -1) { - while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:")) != -1) { + while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:W:")) != -1) { switch (c) { /*case 'f': write_output_file = 1; @@ -251,7 +252,7 @@ int main(int argc, char **argv) case 'y': n_tx = atoi(optarg); - if ((n_tx == 0) || (n_tx > 2)) { + if ((n_tx == 0) || (n_tx > 4)) { printf("Unsupported number of TX antennas %d. Exiting.\n", n_tx); exit(-1); } @@ -261,7 +262,7 @@ int main(int argc, char **argv) case 'z': n_rx = atoi(optarg); - if ((n_rx == 0) || (n_rx > 2)) { + if ((n_rx == 0) || (n_rx > 4)) { printf("Unsupported number of RX antennas %d. Exiting.\n", n_rx); exit(-1); } @@ -299,6 +300,10 @@ int main(int argc, char **argv) printf("Illegal PBCH phase (0-3) got %d\n", pbch_phase); break;*/ + case 'W': + Nl = atoi(optarg); + break; + case 'm': Imcs = atoi(optarg); #ifdef DEBUG_NR_ULSCHSIM @@ -335,13 +340,14 @@ int main(int argc, char **argv) printf("-z Number of RX antennas used in UE\n"); //printf("-i Relative strength of first intefering eNB (in dB) - cell_id mod 3 = 1\n"); //printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n"); + printf("-W number of layer\n"); printf("-M Multiple SSB positions in burst\n"); printf("-N Nid_cell\n"); printf("-R N_RB_UL\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); - printf("-m\n"); - printf("-l\n"); - printf("-r\n"); + printf("-m MCS\n"); + printf("-l number of symbol\n"); + printf("-r number of RB\n"); //printf("-O oversampling factor (1,2,4,8,16)\n"); //printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); @@ -359,8 +365,8 @@ int main(int argc, char **argv) snr1 = snr0 + 10; gNB2UE = new_channel_desc_scm(n_tx, - n_rx, - channel_model, + n_rx, + channel_model, 61.44e6, //N_RB2sampling_rate(N_RB_DL), 40e6, //N_RB2channel_bandwidth(N_RB_DL), DS_TDL, @@ -426,8 +432,7 @@ int main(int argc, char **argv) uint8_t length_dmrs = 1; uint8_t N_PRB_oh; uint16_t N_RE_prime,code_rate; - unsigned char mod_order; - uint8_t Nl = 1; + unsigned char mod_order; uint8_t rvidx = 0; uint8_t UE_id = 0; @@ -437,9 +442,14 @@ int main(int argc, char **argv) NR_UE_ULSCH_t *ulsch_ue = UE->ulsch[0][0][0]; + if ((Nl==4)||(Nl==3)) + { + nb_re_dmrs = nb_re_dmrs*2; + } + mod_order = nr_get_Qm_ul(Imcs, 0); code_rate = nr_get_code_rate_ul(Imcs, 0); - available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1); + available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, Nl); TBS = nr_compute_tbs(mod_order,code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, 0, Nl); printf("\nAvailable bits %u TBS %u mod_order %d\n", available_bits, TBS, mod_order); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 69316d6b88..b6cfae3fe1 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -282,7 +282,7 @@ int main(int argc, char **argv) int gNB_id = 0; int ap; int tx_offset; - int32_t txlev=0; + int32_t txlev_sum = 0, atxlev[4]; int start_rb = 0; int UE_id =0; // [hna] only works for UE_id = 0 because NUMBER_OF_NR_UE_MAX is set to 1 (phy_init_nr_gNB causes segmentation fault) float target_error_rate = 0.01; @@ -307,7 +307,7 @@ int main(int argc, char **argv) uint16_t ptrsSymbPerSlot = 0; uint16_t ptrsRePerSymb = 0; - uint8_t transform_precoding = 1; // 0 - ENABLE, 1 - DISABLE + uint8_t transformPrecoder = transformPrecoder_disabled; // 0 - ENABLE, 1 - DISABLE uint8_t num_dmrs_cdm_grps_no_data = 1; uint8_t mcs_table = 0; @@ -329,7 +329,7 @@ int main(int argc, char **argv) /* initialize the sin-cos table */ InitSinLUT(); - while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:ikl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z")) != -1) { + while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:kl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z:W:")) != -1) { printf("handling optarg %c\n",c); switch (c) { @@ -363,8 +363,8 @@ int main(int argc, char **argv) scg_fd = fopen(optarg, "r"); if (scg_fd == NULL) { - printf("Error opening %s\n", optarg); - exit(-1); + printf("Error opening %s\n", optarg); + exit(-1); } break; @@ -437,6 +437,10 @@ int main(int argc, char **argv) case 'm': Imcs = atoi(optarg); break; + + case 'W': + precod_nbr_layers = atoi(optarg); + break; case 'n': n_trials = atoi(optarg); @@ -485,9 +489,9 @@ int main(int argc, char **argv) case 'y': n_tx = atoi(optarg); - if ((n_tx == 0) || (n_tx > 2)) { - printf("Unsupported number of tx antennas %d\n", n_tx); - exit(-1); + if ((n_tx == 0) || (n_tx > 4)) { + printf("Unsupported number of tx antennas %d\n", n_tx); + exit(-1); } break; @@ -496,8 +500,8 @@ int main(int argc, char **argv) n_rx = atoi(optarg); if ((n_rx == 0) || (n_rx > 8)) { - printf("Unsupported number of rx antennas %d\n", n_rx); - exit(-1); + printf("Unsupported number of rx antennas %d\n", n_rx); + exit(-1); } break; @@ -506,8 +510,8 @@ int main(int argc, char **argv) input_fd = fopen(optarg, "r"); if (input_fd == NULL) { - printf("Problem with filename %s\n", optarg); - exit(-1); + printf("Problem with filename %s\n", optarg); + exit(-1); } break; @@ -568,11 +572,11 @@ int main(int argc, char **argv) case 'Z': - transform_precoding = 0; // enabled + transformPrecoder = transformPrecoder_enabled; num_dmrs_cdm_grps_no_data = 2; mcs_table = 3; - printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transform_precoding); + printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transformPrecoder); break; @@ -611,6 +615,7 @@ int main(int argc, char **argv) printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n"); printf("-Q If -F used, read parameters from file\n"); printf("-Z If -Z is used, SC-FDMA or transform precoding is enabled in Uplink \n"); + printf("-W Num of layer for PUSCH\n"); exit(-1); break; @@ -713,7 +718,7 @@ int main(int argc, char **argv) prepare_scd(scd); - fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); + fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); @@ -724,9 +729,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,0, 0, NULL); + rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; @@ -870,14 +875,18 @@ int main(int argc, char **argv) uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); printf("num dmrs sym %d\n",number_dmrs_symbols); uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; - - // if transform precoding is enabled - if (transform_precoding == 0) { + + if ((frame_parms->nb_antennas_tx==4)&&(precod_nbr_layers==4)) + { + num_dmrs_cdm_grps_no_data = 2; + } + + if (transformPrecoder == transformPrecoder_enabled) { AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); int8_t index = get_index_for_dmrs_lowpapr_seq((NR_NB_SC_PER_RB/2) * nb_rb); - AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); dmrs_config_type = pusch_dmrs_type1; @@ -886,7 +895,7 @@ int main(int argc, char **argv) nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; - unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1); + unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, precod_nbr_layers); unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); @@ -1082,14 +1091,14 @@ int main(int argc, char **argv) pusch_pdu->mcs_table = mcs_table; pusch_pdu->target_code_rate = code_rate; pusch_pdu->qam_mod_order = mod_order; - pusch_pdu->transform_precoding = transform_precoding; + pusch_pdu->transformPrecoder = transformPrecoder; pusch_pdu->data_scrambling_id = *scc->physCellId; - pusch_pdu->nrOfLayers = 1; + pusch_pdu->nrOfLayers = precod_nbr_layers; pusch_pdu->ul_dmrs_symb_pos = l_prime_mask; pusch_pdu->dmrs_config_type = dmrs_config_type; pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; pusch_pdu->scid = 0; - pusch_pdu->dmrs_ports = 1; + pusch_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; pusch_pdu->resource_alloc = 1; pusch_pdu->rb_start = start_rb; @@ -1109,7 +1118,7 @@ int main(int argc, char **argv) pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; // if transform precoding is enabled - if (transform_precoding == 0) { + if (transformPrecoder == transformPrecoder_enabled) { pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; // U as defined in 38.211 section 6.4.1.1.1.2 pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; // V as defined in 38.211 section 6.4.1.1.1.2 @@ -1167,10 +1176,10 @@ int main(int argc, char **argv) ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t)); ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; - ul_config.ul_config_list[0].pusch_config_pdu.transform_precoding = transform_precoding; + ul_config.ul_config_list[0].pusch_config_pdu.transformPrecoder = transformPrecoder; // if transform precoding is enabled - if (transform_precoding == 0) { + if (transformPrecoder == transformPrecoder_enabled) { ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_group_number = *scc->physCellId % 30;// U as defined in 38.211 section 6.4.1.1.1.2 ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;// V as defined in 38.211 section 6.4.1.1.1.2 @@ -1198,28 +1207,54 @@ int main(int argc, char **argv) LOG_D(PHY, "Sending Uplink data \n"); nr_ue_pusch_common_procedures(UE, slot, - &UE->frame_parms,1); - - if (n_trials==1) { - LOG_M("txsig0.m","txs0", UE->common_vars.txdata[0],frame_parms->samples_per_subframe*10,1,1); + &UE->frame_parms, + frame_parms->nb_antennas_tx); + + + if (n_trials==1) + { + LOG_M("txsig0.m","txs0", &UE->common_vars.txdata[0][slot_offset],slot_length,1,1); LOG_M("txsig0F.m","txs0F", UE->common_vars.txdataF[0],frame_parms->ofdm_symbol_size*14,1,1); + if (precod_nbr_layers > 1) + { + LOG_M("txsig1.m","txs1", &UE->common_vars.txdata[1][slot_offset],slot_length,1,1); + LOG_M("txsig1F.m","txs1F", UE->common_vars.txdataF[1],frame_parms->ofdm_symbol_size*14,1,1); + if (precod_nbr_layers==4) + { + LOG_M("txsig2.m","txs2", &UE->common_vars.txdata[2][slot_offset],slot_length,1,1); + LOG_M("txsig3.m","txs3", &UE->common_vars.txdata[3][slot_offset],slot_length,1,1); + + LOG_M("txsig2F.m","txs2F", UE->common_vars.txdataF[2],frame_parms->ofdm_symbol_size*14,1,1); + LOG_M("txsig3F.m","txs3F", UE->common_vars.txdataF[3],frame_parms->ofdm_symbol_size*14,1,1); + } + } } /////////// //////////////////////////////////////////////////// tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); - - txlev = signal_energy(&UE->common_vars.txdata[0][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], + txlev_sum = 0; + for (int aa=0; aanb_antennas_tx; aa++) + { + atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); - } - else n_trials = 1; + + txlev_sum += atxlev[aa]; + + if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,atxlev[aa],10*log10((double)atxlev[aa]),txlev_sum); + } + } + else + { + n_trials = 1; + } - if (input_fd == NULL ) { - - sigma_dB = 10 * log10((double)txlev * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; + if (input_fd == NULL ) + { + sigma_dB = 10 * log10((double)txlev_sum * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; sigma = pow(10,sigma_dB/10); - if(n_trials==1) printf("sigma %f (%f dB), txlev %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev),(double)(double) + if(n_trials==1) printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev_sum),(double)(double) frame_parms->ofdm_symbol_size/(12*nb_rb)); for (i=0; imax_Doppler == 0) { + if (UE2gNB->max_Doppler == 0) + { multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); } else { multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); } - for (i=0; inb_antennas_rx; ap++) { + for (i=0; inb_antennas_rx; ap++) + { + if (channel_model == AWGN) + { + double H_awgn[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 + {0.0, 1.0, 0.0, 0.0}, //rx 1 + {0.0, 0.0, 1.0, 0.0}, //rx 2 + {0.0, 0.0, 0.0, 1.0}};//rx 3 + #if 0 + double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 + {0.5, 1.0, 0.5, 0.25}, //rx 1 + {0.25, 0.5, 1.0, 0.5}, //rx 2 + {0.125, 0.25, 0.5, 1.0}};//rx 3 + #endif + // sum up signals from different Tx antennas + r_re[ap][i] = 0; + r_im[ap][i] = 0; + + for (int aa=0; aaofdm_symbol_size/(12*nb_rb))) - SNR;; + sigma = pow(10,sigma_dB/10); + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); + + #if 0 + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i])); // convert to fixed point + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i])); + + + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) ] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i) ]; // convert to fixed point + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i)+1 ]; + #endif + /* Add phase noise if enabled */ if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)], @@ -1250,7 +1324,8 @@ int main(int argc, char **argv) } /*End input_fd */ - if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) + { set_ptrs_symb_idx(&ptrsSymPos, pusch_pdu->nr_of_symbols, pusch_pdu->start_symbol_index, @@ -1268,24 +1343,37 @@ int main(int argc, char **argv) gNB->UL_INFO.rx_ind.number_of_pdus = 0; gNB->UL_INFO.crc_ind.number_crcs = 0; - phy_procedures_gNB_common_RX(gNB, frame, slot); + phy_procedures_gNB_common_RX(gNB, frame, slot); - ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); + ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); - if (n_trials==1 && round==0) { + if (n_trials==1 && round==0) + { LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1); - LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0]+start_symbol*frame_parms->ofdm_symbol_size,nb_symb_sch*frame_parms->ofdm_symbol_size,1,1); - + LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],14*frame_parms->ofdm_symbol_size,1,1); + if (precod_nbr_layers > 1) + { + LOG_M("rxsig1.m","rx1",&gNB->common_vars.rxdata[1][slot_offset],slot_length,1,1); + LOG_M("rxsigF1.m","rxsF1",gNB->common_vars.rxdataF[1],14*frame_parms->ofdm_symbol_size,1,1); + if (precod_nbr_layers==4) + { + LOG_M("rxsig2.m","rx2",&gNB->common_vars.rxdata[2][slot_offset],slot_length,1,1); + LOG_M("rxsig3.m","rx3",&gNB->common_vars.rxdata[3][slot_offset],slot_length,1,1); + + LOG_M("rxsigF2.m","rxsF2",gNB->common_vars.rxdataF[2],14*frame_parms->ofdm_symbol_size,1,1); + LOG_M("rxsigF3.m","rxsF3",gNB->common_vars.rxdataF[3],14*frame_parms->ofdm_symbol_size,1,1); + } + } } if (n_trials == 1 && round==0) { -#ifdef __AVX2__ + #ifdef __AVX2__ int off = ((nb_rb&1) == 1)? 4:0; -#else + #else int off = 0; -#endif + #endif LOG_M("rxsigF0_ext.m","rxsF0_ext", &gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); @@ -1298,11 +1386,77 @@ int main(int argc, char **argv) (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_M("rxsigF0_comp.m","rxsF0_comp", &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_M("chmagF0.m","chmF0", - &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_M("chmagbF0.m","chmbF0", - &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - if (n_rx == 2) { + LOG_M("chmagF0.m","chmF0", + &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chmagbF0.m","chmbF0", + &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_llrlayers0.m","rxsF0_llrlayers0", + &gNB->pusch_vars[0]->llr_layers[0][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + + if (precod_nbr_layers==2) + { + LOG_M("rxsigF1_ext.m","rxsF1_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + + LOG_M("chestF3.m","chF3", + &gNB->pusch_vars[0]->ul_ch_estimates[3][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); + + LOG_M("chestF3_ext.m","chF3_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + + LOG_M("rxsigF2_comp.m","rxsF2_comp", + &gNB->pusch_vars[0]->rxdataF_comp[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + + LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", + &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + + } + + if (precod_nbr_layers==4) + { + LOG_M("rxsigF1_ext.m","rxsF1_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF2_ext.m","rxsF2_ext", + &gNB->pusch_vars[0]->rxdataF_ext[2][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF3_ext.m","rxsF3_ext", + &gNB->pusch_vars[0]->rxdataF_ext[3][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + + LOG_M("chestF5.m","chF5", + &gNB->pusch_vars[0]->ul_ch_estimates[5][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); + LOG_M("chestF10.m","chF10", + &gNB->pusch_vars[0]->ul_ch_estimates[10][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); + LOG_M("chestF15.m","chF15", + &gNB->pusch_vars[0]->ul_ch_estimates[15][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); + + + LOG_M("chestF5_ext.m","chF5_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[5][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chestF10_ext.m","chF10_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[10][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chestF15_ext.m","chF15_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[15][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + + + LOG_M("rxsigF4_comp.m","rxsF4_comp", + &gNB->pusch_vars[0]->rxdataF_comp[4][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF8_comp.m","rxsF8_comp", + &gNB->pusch_vars[0]->rxdataF_comp[8][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF12_comp.m","rxsF12_comp", + &gNB->pusch_vars[0]->rxdataF_comp[12][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", + &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + LOG_M("rxsigF0_llrlayers2.m","rxsF0_llrlayers2", + &gNB->pusch_vars[0]->llr_layers[2][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + LOG_M("rxsigF0_llrlayers3.m","rxsF0_llrlayers3", + &gNB->pusch_vars[0]->llr_layers[3][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + } + + #if 0 + if (n_rx == 2) { LOG_MM("rxsigF0_comp.m","rxsF1_comp", &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_MM("rxsigF0_ext.m","rxsF1_ext", @@ -1349,9 +1503,10 @@ int main(int argc, char **argv) LOG_MM("chmagbF0.m","chmbF3", &gNB->pusch_vars[0]->ul_ch_magb[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); } + #endif LOG_M("rxsigF0_llr.m","rxsF0_llr", - &gNB->pusch_vars[0]->llr[0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); } //////////////////////////////////////////////////////////// diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 3f4be9dd58..7e5be9eeba 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2708,6 +2708,9 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, LOG_D(NR_MAC,"dci_pdu->srs_resource_indicator.nbits %d\n",dci_pdu->srs_resource_indicator.nbits); // Precoding info and number of layers long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); + + pusch_antenna_ports = *pusch_Config->maxRank; + dci_pdu->precoding_information.nbits=0; if (pusch_Config && pusch_Config->txConfig != NULL){ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index c23d4bb073..963723725f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -190,7 +190,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con else transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; } - + pusch_config_pdu->transformPrecoder = transformPrecoder; /* PRECOD_NBR_LAYERS */ if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)); @@ -198,11 +198,12 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)){ - uint8_t n_antenna_port = 0; //FIXME!!! + uint8_t n_antenna_port = mac->phy_config.config_req.carrier_config.num_tx_ant; if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits - if (n_antenna_port == 4){ // 4 antenna port and the higher layer parameter txConfig = codebook + if (n_antenna_port == 4) + { // 4 antenna port and the higher layer parameter txConfig = codebook // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4 if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) @@ -212,54 +213,56 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; } } // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1 if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) - && (*pusch_Config->maxRank == 1)){ + && (*pusch_Config->maxRank == 1)) + { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; } } } - if (n_antenna_port == 4){ // 2 antenna port and the higher layer parameter txConfig = codebook + if (n_antenna_port == 2) + { // 2 antenna port and the higher layer parameter txConfig = codebook // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2 - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)){ - + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) + { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; } } @@ -267,16 +270,17 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1 if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) - && (*pusch_Config->maxRank == 1)){ + && (*pusch_Config->maxRank == 1)) + { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; } if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18]; - pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; + pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; } } @@ -285,9 +289,9 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con /*-------------------- Changed to enable Transform precoding in RF SIM------------------------------------------------*/ - /*if (pusch_config_pdu->transform_precoding == transform_precoder_enabled) { + /*if (pusch_config_pdu->transformPrecoder == transformPrecoder_enabled) { - pusch_config_dedicated->transform_precoder = transform_precoder_enabled; + pusch_config_dedicated->transform_precoder = transformPrecoder_enabled; if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) { @@ -309,7 +313,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con } } else - pusch_config_dedicated->transform_precoder = transform_precoder_disabled;*/ + pusch_config_dedicated->transformPrecoder = ttransformPrecoder_disabled;*/ } // todo: this function shall be reviewed completely because of the many comments left by the author @@ -342,7 +346,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf } long *max_length = NULL; long *dmrs_type = NULL; - LOG_D(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); + LOG_I(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) { max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength; @@ -353,7 +357,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type; } - LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); + LOG_I(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC @@ -369,35 +373,32 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf } if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && - (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11 + (dmrs_type == NULL) && (max_length == NULL)) + { // tables 7.3.1.1.2-8/9/10/11 + + if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)) + { + rank = pusch_config_pdu->nrOfLayers; + } if (rank == 1) { - pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC - pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val); //TBC + pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; + pusch_config_pdu->dmrs_ports =1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val)); } if (rank == 2){ - pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC - pusch_config_pdu->dmrs_ports = 0; //FIXME - //pusch_config_pdu->dmrs_ports[0] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?0:2):0; - //pusch_config_pdu->dmrs_ports[1] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?2:3):1; + pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; + pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val> 2)?0x5:0xc):0x3; } if (rank == 3){ - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC - pusch_config_pdu->dmrs_ports = 0; //FIXME - //pusch_config_pdu->dmrs_ports[0] = 0; - //pusch_config_pdu->dmrs_ports[1] = 1; - //pusch_config_pdu->dmrs_ports[2] = 2; + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + pusch_config_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = 2; //TBC - pusch_config_pdu->dmrs_ports = 0; //FIXME - //pusch_config_pdu->dmrs_ports[0] = 0; - //pusch_config_pdu->dmrs_ports[1] = 1; - //pusch_config_pdu->dmrs_ports[2] = 2; - //pusch_config_pdu->dmrs_ports[3] = 3; + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + pusch_config_pdu->dmrs_ports = ((1<n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME } } - LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); + LOG_I(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); } // Configuration of Msg3 PDU according to clauses: @@ -542,6 +543,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1; pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; pusch_config_pdu->nrOfLayers = 1; + pusch_config_pdu->Tpmi = 0; pusch_config_pdu->rnti = rnti; NR_BWP_UplinkCommon_t *initialUplinkBWP; if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; @@ -634,7 +636,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->scid = 0; // Transform precoding according to 6.1.3 UE procedure for applying transform precoding on PUSCH in 38.214 - pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out + pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214 pusch_config_pdu->resource_alloc = (mac->cg) ? pusch_Config->resourceAllocation : 1; @@ -680,7 +682,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, /* Transform precoding */ if (rnti_type != NR_RNTI_CS || (rnti_type == NR_RNTI_CS && dci->ndi == 1)) { - pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); + pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); } /*DCI format-related configuration*/ @@ -716,7 +718,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/ - if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { + if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; @@ -761,7 +763,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->mcs_index = dci->mcs; /* MCS TABLE */ - if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { + if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_Table : NULL, 0, *dci_format, rnti_type, target_ss, false); } else { pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, 1, *dci_format, rnti_type, target_ss, false); @@ -798,9 +800,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if ((mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; - else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) + if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) + { + if (*dci_format != NR_UL_DCI_FORMAT_0_1) + { + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; + } + } + else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)) pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; // Num PRB Overhead from PUSCH-ServingCellConfig @@ -821,7 +828,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup && mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB && mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { - if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { + if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { nfapi_nr_ue_ptrs_ports_t ptrs_ports_list; pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list; valid_ptrs_setup = set_ul_ptrs_values(mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup, @@ -909,6 +916,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id); if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) + LOG_I(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); mac->if_module->scheduled_response(&scheduled_response); } else { @@ -1022,6 +1030,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, rx_frame, rx_slot, ul_info->thread_id); if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){ + LOG_I(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); mac->if_module->scheduled_response(&scheduled_response); } pthread_mutex_lock(&ul_config->mutex_ul_config); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 1cb3fdb708..d9c98852a3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -388,7 +388,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts; AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n"); cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG; - LOG_I(NR_MAC,"Set TX/RX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); + LOG_I(NR_MAC,"Set RX antenna number to %d, Set TX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,cfg->carrier_config.num_rx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); AssertFatal(cfg->carrier_config.num_tx_ant.value > 0,"carrier_config.num_tx_ant.value %d !\n",cfg->carrier_config.num_tx_ant.value ); cfg->num_tlv++; cfg->num_tlv++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 6ac7f3f82e..5de36bb2db 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -977,9 +977,9 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) - pusch_pdu->transform_precoding = 1; + pusch_pdu->transformPrecoder = 1; else - pusch_pdu->transform_precoding = 0; + pusch_pdu->transformPrecoder = 0; pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = 1; pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index abc007197d..9cbbe7d9a1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1139,13 +1139,14 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; LOG_D(NR_MAC, "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " - "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", + "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", frame, slot, dci_payload.frequency_domain_assignment.val, pdsch_pdu->rbStart, pdsch_pdu->rbSize, pdsch_pdu->BWPSize, + pdsch_pdu->nrOfLayers, dci_payload.time_domain_assignment.val, dci_payload.vrb_to_prb_mapping.val, dci_payload.mcs, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index f1005cea70..8f7c856a30 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -405,6 +405,7 @@ void nr_preprocessor_phytest(module_id_t module_id, uint32_t target_ul_mcs = 9; uint32_t target_ul_bw = 50; +uint32_t target_ul_Nl = 1; uint64_t ulsch_slot_bitmap = (1 << 8); bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot) { @@ -446,15 +447,21 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; - const uint8_t num_dmrs_cdm_grps_no_data = 1; + uint8_t num_dmrs_cdm_grps_no_data = 1; + if ((target_ul_Nl==4)||(target_ul_Nl==3)) + { + num_dmrs_cdm_grps_no_data = 2; + } + /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format + || ps->nrOfLayers != target_ul_Nl || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); uint16_t rbStart = 0; uint16_t rbSize; @@ -525,6 +532,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; /* Calculate TBS from MCS */ + ps->nrOfLayers = target_ul_Nl; sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); if (ps->pusch_Config->tp_pi2BPSK @@ -539,7 +547,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ ps->N_PRB_DMRS * ps->num_dmrs_symb, 0, // nb_rb_oh 0, - 1 /* NrOfLayers */) + ps->nrOfLayers /* NrOfLayers */) >> 3; /* mark the corresponding RBs as used */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1c0cb0353e..4583da876f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -355,6 +355,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, + uint8_t nrOfLayers, NR_pusch_semi_static_t *ps) { ps->dci_format = dci_format; @@ -371,11 +372,11 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, ps->pusch_Config = ubwp?ubwp->bwp_Dedicated->pusch_Config->choice.setup:(ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) - ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; + ps->transformPrecoder = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; else - ps->transform_precoding = *ps->pusch_Config->transformPrecoder; + ps->transformPrecoder = *ps->pusch_Config->transformPrecoder; const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - if (ps->transform_precoding) + if (ps->transformPrecoder) ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_Table : NULL, 0, ps->dci_format, @@ -392,6 +393,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, num_dmrs_cdm_grps_no_data = 2; // in case of transform precoding - no Data sent in DMRS symbol } + ps->nrOfLayers = nrOfLayers; ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; /* DMRS calculations */ @@ -689,8 +691,21 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, "Non Codebook configuration non supported\n"); dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS } + AssertFatal((pusch_pdu->Tpmi==0), "unsupport Tpmi\n"); + dci_pdu_rel15->precoding_information.val= 0; + if (pusch_pdu->nrOfLayers == 2) + { + dci_pdu_rel15->precoding_information.val = 4; + } + else if (pusch_pdu->nrOfLayers == 4) + { + dci_pdu_rel15->precoding_information.val = 11; + } + + // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports - dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank + dci_pdu_rel15->antenna_ports.val = 0; + // DMRS sequence initialization dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid; break; @@ -699,11 +714,14 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, } LOG_D(NR_MAC, - "%s() ULDCI type 0 payload: freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n", + "%s() ULDCI type 0 payload: dci_format %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, precoding_information.val %d antenna_ports.val %d mcs %d tpc %d ndi %d rv %d\n", __func__, + dci_format, dci_pdu_rel15->frequency_domain_assignment.val, dci_pdu_rel15->time_domain_assignment.val, dci_pdu_rel15->frequency_hopping_flag.val, + dci_pdu_rel15->precoding_information.val, + dci_pdu_rel15->antenna_ports.val, dci_pdu_rel15->mcs, dci_pdu_rel15->tpc, dci_pdu_rel15->ndi, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 9a6fa32b5f..269d6c5359 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -905,7 +905,7 @@ bool allocate_ul_retransmission(module_id_t module_id, NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; int rbStart = 0; // wrt BWP start const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - + const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; const int tda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); @@ -926,8 +926,9 @@ bool allocate_ul_retransmission(module_id_t module_id, if (ps->time_domain_allocation != tda || ps->dci_format != dci_format + || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); } else { /* the retransmission will use a different time domain allocation, check @@ -939,7 +940,7 @@ bool allocate_ul_retransmission(module_id_t module_id, rbSize++; NR_pusch_semi_static_t temp_ps; int dci_format = get_dci_format(sched_ctrl); - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, &temp_ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, &temp_ps); uint32_t new_tbs; uint16_t new_rbSize; bool success = nr_find_nb_rb(retInfo->Qm, @@ -1094,7 +1095,7 @@ void pf_ul(module_id_t module_id, if (max_num_ue < 0) return; - LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d\n", min_rb, rbStart); + LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", min_rb, rbStart, ps->num_dmrs_cdm_grps_no_data); while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; if (rbStart + min_rb >= bwpSize) { LOG_W(NR_MAC, "cannot allocate continuous UL data for UE %d/RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d\n", @@ -1106,13 +1107,15 @@ void pf_ul(module_id_t module_id, /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ + const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; int dci_format = get_dci_format(sched_ctrl); const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format + || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data,nrOfLayers, ps); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = 9; update_ul_ue_R_Qm(sched_pusch, ps); @@ -1125,7 +1128,7 @@ void pf_ul(module_id_t module_id, ps->N_PRB_DMRS * ps->num_dmrs_symb, 0, // nb_rb_oh 0, - 1 /* NrOfLayers */) + ps->nrOfLayers) >> 3; /* Mark the corresponding RBs as used */ @@ -1205,13 +1208,15 @@ void pf_ul(module_id_t module_id, /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ + const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; int dci_format = get_dci_format(sched_ctrl); const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format + || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); update_ul_ue_R_Qm(sched_pusch, ps); /* Calculate the current scheduling bytes and the necessary RBs */ @@ -1473,7 +1478,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) sched_ctrl->last_ul_slot = sched_pusch->slot; LOG_D(NR_MAC, - "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", + "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", frame, slot, rnti, @@ -1486,6 +1491,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->nrOfSymbols, ps->ul_dmrs_symb_pos, sched_pusch->mcs, + ps->nrOfLayers, + ps->num_dmrs_cdm_grps_no_data, sched_pusch->tb_size, harq_id, cur_harq->round, @@ -1532,17 +1539,18 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->qam_mod_order = sched_pusch->Qm; pusch_pdu->mcs_index = sched_pusch->mcs; pusch_pdu->mcs_table = ps->mcs_table; - pusch_pdu->transform_precoding = ps->transform_precoding; + pusch_pdu->transformPrecoder = ps->transformPrecoder; if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; else pusch_pdu->data_scrambling_id = *scc->physCellId; - pusch_pdu->nrOfLayers = 1; + pusch_pdu->nrOfLayers = ps->nrOfLayers; + pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; /* FAPI: DMRS */ pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos; pusch_pdu->dmrs_config_type = ps->dmrs_config_type; - if (pusch_pdu->transform_precoding) { // transform precoding disabled + if (pusch_pdu->transformPrecoder) { // transform precoding disabled long *scramblingid=NULL; if (ps->NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; @@ -1562,7 +1570,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) } pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; - pusch_pdu->dmrs_ports = 1; + pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); /* FAPI: Pusch Allocation in frequency domain */ pusch_pdu->resource_alloc = 1; //type 1 @@ -1588,7 +1596,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); /* TRANSFORM PRECODING --------------------------------------------------------*/ - if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ + if (pusch_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled){ // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 91221276b0..8a560580c9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -298,6 +298,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, + uint8_t nrOfLayers, NR_pusch_semi_static_t *ps); uint8_t nr_get_tpc(int target, uint8_t cqi, int incr); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 27f42f4b1d..66b10dad42 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -318,13 +318,14 @@ typedef struct NR_sched_pucch { typedef struct NR_pusch_semi_static_t { int dci_format; int time_domain_allocation; + uint8_t nrOfLayers; uint8_t num_dmrs_cdm_grps_no_data; int startSymbolIndex; int nrOfSymbols; NR_PUSCH_Config_t *pusch_Config; - uint8_t transform_precoding; + uint8_t transformPrecoder; uint8_t mcs_table; long mapping_type; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ff6923429e..52d03b5e56 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1867,6 +1867,7 @@ int16_t do_RRCReconfiguration( // 1, // 1, // carrier->pdsch_AntennaPorts, + // carrier->pusch_AntennaPorts, // carrier->initial_csi_index[ue_context_p->local_uid + 1], // ue_context_pP->local_uid); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 9465b9b4b0..6a94450450 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -79,6 +79,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco int scg_id, int servCellIndex, int dl_antenna_ports, + int ul_antenna_ports, int do_csirs, int initial_csi_index, int uid); @@ -90,6 +91,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon NR_RRCReconfiguration_IEs_t *reconfig, NR_CellGroupConfig_t *secondaryCellGroup, int dl_antenna_ports, + int ul_antenna_ports, int do_csirs, int initial_csi_index, int uid); diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index f9fce48f41..22e43cbb6a 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -241,6 +241,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ reconfig_ies, ue_context_p->ue_context.secondaryCellGroup, carrier->pdsch_AntennaPorts, + carrier->pusch_AntennaPorts, carrier->do_CSIRS, carrier->initial_csi_index[ue_context_p->local_uid + 1], ue_context_p->local_uid); @@ -250,6 +251,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ reconfig_ies, ue_context_p->ue_context.secondaryCellGroup, carrier->pdsch_AntennaPorts, + carrier->pusch_AntennaPorts, carrier->do_CSIRS, carrier->initial_csi_index[ue_context_p->local_uid + 1], ue_context_p->local_uid); @@ -348,7 +350,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ rrc_mac_config_req_gNB(rrc->module_id, rrc->carrier.ssb_SubcarrierOffset, rrc->carrier.pdsch_AntennaPorts, - rrc->carrier.pusch_AntennaPorts, + rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, rrc->carrier.servingcellconfigcommon, &rrc->carrier.mib, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 980bd39c37..d03f361502 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -55,6 +55,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco int scg_id, int servCellIndex, int dl_antenna_ports, + int ul_antenna_ports, int do_csirs, int initial_csi_index, int uid) { @@ -745,14 +746,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pusch_Config->codebookSubset=calloc(1,sizeof(*pusch_Config->codebookSubset)); *pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent; pusch_Config->maxRank=calloc(1,sizeof(*pusch_Config->maxRank)); - *pusch_Config->maxRank= 1; + *pusch_Config->maxRank= ul_antenna_ports; pusch_Config->rbg_Size=NULL; pusch_Config->uci_OnPUSCH=NULL; pusch_Config->tp_pi2BPSK=NULL; /*------------------------------TRANSFORM PRECODING- -----------------------------------------------------------------------*/ - uint8_t transform_precoding = NR_PUSCH_Config__transformPrecoder_disabled; + uint8_t transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; // TBD: configure this from .conf file, Dedicated params cannot yet be configured in .conf file. // Enable this to test transform precoding enabled from dedicated config. @@ -764,13 +765,13 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco if (pusch_Config->transformPrecoder == NULL) { if (servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder != NULL) - transform_precoding = NR_PUSCH_Config__transformPrecoder_enabled; + transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled; } else - transform_precoding = *pusch_Config->transformPrecoder; + transformPrecoder = *pusch_Config->transformPrecoder; - if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled ) { + if (transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled ) { /* Enable DMRS uplink config for transform precoding enabled */ NR_DMRS_UplinkConfig->transformPrecodingEnabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingEnabled)); NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity = NULL; @@ -1348,6 +1349,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon NR_RRCReconfiguration_IEs_t *reconfig, NR_CellGroupConfig_t *secondaryCellGroup, int dl_antenna_ports, + int ul_antenna_ports, int do_csirs, int initial_csi_index, int uid) { @@ -1363,6 +1365,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon 1, 1, dl_antenna_ports, + ul_antenna_ports, do_csirs, initial_csi_index, uid); diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 13945998d7..20faa86591 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -429,7 +429,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp if (!alreadyLocked) pthread_mutex_lock(&Sockmutex); - LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); + LOG_D(HW,"sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt); for (int i=0; ibuf[i]; @@ -623,7 +623,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } rfsimulator_state_t *t = device->priv; - LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps); + LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld, nbAnt %d\n", nsamps, t->nextTimestamp+nsamps, nbAnt); // deliver data from received data // check if a UE is connected int first_sock; @@ -728,6 +728,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest for (int a=0; achannel_model != NULL ) // apply a channel model + { rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a], a, ptr->channel_model, @@ -735,11 +736,21 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest t->nextTimestamp, CirSize ); - else { // no channel modeling + } + else + { // no channel modeling + + #if 0 double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 {0.5, 1.0, 0.5, 0.25}, //rx 1 {0.25, 0.5, 1.0, 0.5}, //rx 2 {0.125, 0.25, 0.5, 1.0}};//rx 3 + #else + double H_awgn_mimo[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 + {0.0, 1.0, 0.0, 0.0},//rx 1 + {0.0, 0.0, 1.0, 0.0},//rx 2 + {0.0, 0.0, 0.0, 1.0}};//rx 3 + #endif sample_t *out=(sample_t *)samplesVoid[a]; int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf new file mode 100644 index 0000000000..74f2f9c11c --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf @@ -0,0 +1,320 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ + mcc = 208; + mnc = 99; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + sd = 0x1; // 0 false, else true + }, + { + sst = 1; + sd = 0x112233; // 0 false, else true + } + ); + + }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 4; + pusch_AntennaPorts = 4; + sib1_tda = 0; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 12; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641280; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640008; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; #for DL slot + initialDLBWPmappingType_0 = 0; #0=typeA,1=typeB + initialDLBWPstartSymbolAndLength_0 = 40; #this is SS=1,L=13 + + initialDLBWPk0_1 = 0; #for mixed slot + initialDLBWPmappingType_1 = 0; + initialDLBWPstartSymbolAndLength_1 = 57; #this is SS=1,L=5 + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 6; # used for UL slot + initialULBWPmappingType_0 = 1 + initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13 + + initialULBWPk2_1 = 6; # used for mixed slot + initialULBWPmappingType_1 = 1; + initialULBWPstartSymbolAndLength_1 = 52; # this is SS=10 L=4 + + initialULBWPk2_2 = 7; # used for Msg.3 during RA + initialULBWPmappingType_2 = 1; + initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4 + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + amf_ip_address = ( { ipv4 = "192.168.70.132"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; + GNB_INTERFACE_NAME_FOR_NGU = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 150; + pucch_TargetSNRx10 = 200; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 8; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 4 + nb_rx = 4 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + #beamforming 1x4 matrix: + bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; + clock_src = "internal"; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +rfsimulator : +{ + serveraddr = "server"; + serverport = "4043"; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + ngap_log_level ="info"; + ngap_log_verbosity ="medium"; + }; + From 2aa8a438f2af6765d042c3024e2208085b806c5c Mon Sep 17 00:00:00 2001 From: Fang Date: Tue, 7 Dec 2021 13:47:15 +0800 Subject: [PATCH 014/226] add mimo doc --- doc/UL_MIMO.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 doc/UL_MIMO.txt diff --git a/doc/UL_MIMO.txt b/doc/UL_MIMO.txt new file mode 100644 index 0000000000..c06bc78c4c --- /dev/null +++ b/doc/UL_MIMO.txt @@ -0,0 +1,31 @@ +# how to build phy sim +cd cmake_targets/ +sudo ./build_oai --phy_simulators -c + +cd phy_simulators/build/ +# ULSCH sim +# bit level validation +# PUSCH encoding and decoding for 4 layers 2 CMD without data +sudo ./nr_ulschsim -R 106 -m9 -s13 -n100 -y4 -z4 -W4 + +# UL sim +# Uplink chain validation +# PUSCH on UE side and gNB side,whole chain for PUSCH +# No channel model on data domain signal +# No cross-path connection +# PMI = 0 is only unitary prcoding matrix +sudo ./nr_ulsim -n100 -m9 -r106 -s13 -W4 -y4 -z4 + +# How to build rfsim +sudo ./build_oai -c --gNB --nrUE -w SIMU + +# How to run with rfsim +# 4x4 RANK 4 +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 4 +sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 +# 4x4 RANK 2 +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 2 +sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 + + + From 9b0d2384ea407a683ffb0e8aa02ff6903a991135 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 9 Dec 2021 12:34:08 +0100 Subject: [PATCH 015/226] minor changes after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 1 - openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 - 2 files changed, 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 125b77df41..3dcecb0286 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -941,7 +941,6 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { int better_rsrp_reported = -140-(-0); /*minimum_measured_RSRP_value - minimum_differntail_RSRP_value*///considering the minimum RSRP value as better RSRP initially uint8_t diff_rsrp_idx = 0; uint8_t i, j; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; if (n_dl_bwp < 4) pdsch_bwp_id = bwp_id; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 4591756c67..743c794546 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1260,7 +1260,6 @@ void fill_initial_SpCellConfig(rnti_t rnti, // frequency domain resources depends on BWP size // options are 24, 48 or 96 coreset->frequencyDomainResources.buf = calloc(1,6); - int curr_bwp = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; if (0) { if (curr_bwp < 48) coreset->frequencyDomainResources.buf[0] = 0xf0; From 79002c119057c7a37fda5d17e9359bae71eadc4c Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 9 Dec 2021 17:37:16 +0100 Subject: [PATCH 016/226] phy-sim test cases for UL-MIMO --- cmake_targets/autotests/test_case_list.xml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 3472b14efc..00fcfc4140 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1182,9 +1182,10 @@ execution - nr_ulschsim Test cases. (Test1: 106 PRB), - (Test2: 217 PRB), - (Test3: 273 PRB) + nr_ulschsim Test cases. (Test1: 106 PRBs), + (Test2: 217 PRBs), + (Test3: 273 PRBs) + (Test4: 106 PRBs 4-layer MIMO) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c @@ -1193,8 +1194,9 @@ $OPENAIR_DIR/targets/bin/nr_ulschsim.Rel15 -R 106 -m9 -s13 -n100 -R 217 -m15 -s15 -n100 - -R 273 -m19 -s20 -n100 - nr_ulschsim.test1 nr_ulschsim.test2 nr_ulschsim.test3 + -R 273 -m19 -s20 -n100 + -R 106 -m9 -s13 -n100 -y4 -z4 -W4 + nr_ulschsim.test1 nr_ulschsim.test2 nr_ulschsim.test3 nr_ulschsim.test4 PUSCH test OK segmentation fault|assertion|exiting|fatal 3 @@ -1302,7 +1304,9 @@ (Test12: SC-FDMA, 216 PRBs), (Test13: SC-FDMA, 273 PRBs), (Test14: SC-FDMA, 3 DMRS), - (Test15: MCS 16 50 PRBs 2 RX_Antenna) + (Test15: MCS 16 50 PRBs 2 RX_Antenna) + (Test16: MCS 9 106 PRBs MIMO 2 layers) + (Test17: MCS 9 106 PRBs MIMO 4 layers) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c @@ -1323,9 +1327,11 @@ -n50 -s5 -Z -r216 -R217 -n50 -s5 -Z -r270 -R273 -n100 -s5 -Z -U 2 0 2 - -n100 -m16 -s10 -z2 + -n100 -m16 -s10 -z2 + -n100 -m9 -r106 -s10 -W2 -y2 -z2 + -n100 -m9 -r106 -s13 -W4 -y4 -z4 - nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 + nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test16 PUSCH test OK segmentation fault|assertion|exiting|fatal 3 From dbdf38133e3f99320f01ac54a3e398802981f35e Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 9 Dec 2021 17:37:55 +0100 Subject: [PATCH 017/226] reducing log levels --- diff_1206_2.txt | 4257 ----------------- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 6 +- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 4 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 14 +- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 4 +- 5 files changed, 14 insertions(+), 4271 deletions(-) delete mode 100644 diff_1206_2.txt diff --git a/diff_1206_2.txt b/diff_1206_2.txt deleted file mode 100644 index ff352f4157..0000000000 --- a/diff_1206_2.txt +++ /dev/null @@ -1,4257 +0,0 @@ -diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h -index c02155326b..1238b43c27 100644 ---- a/executables/nr-softmodem-common.h -+++ b/executables/nr-softmodem-common.h -@@ -67,6 +67,7 @@ - #define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" - #define CONFIG_HLP_DLMCS_PHYTEST "Set the downlink MCS for PHYTEST mode\n" - #define CONFIG_HLP_DLNL_PHYTEST "Set the downlink nrOfLayers for PHYTEST mode\n" -+#define CONFIG_HLP_ULNL_PHYTEST "Set the uplink nrOfLayers for PHYTEST mode\n" - #define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" - #define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" - #define CONFIG_HLP_ULMCS_PHYTEST "Set the uplink MCS for PHYTEST mode\n" -diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h -index 896c363cbf..a11572c0e1 100644 ---- a/executables/nr-softmodem.h -+++ b/executables/nr-softmodem.h -@@ -23,6 +23,7 @@ - {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ - {"m" , CONFIG_HLP_DLMCS_PHYTEST,0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ - {"l" , CONFIG_HLP_DLNL_PHYTEST,0, uptr:&target_dl_Nl, defintval:0, TYPE_UINT, 0}, \ -+ {"L" , CONFIG_HLP_ULNL_PHYTEST,0, uptr:&target_ul_Nl, defintval:0, TYPE_UINT, 0}, \ - {"t" , CONFIG_HLP_ULMCS_PHYTEST,0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ - {"M" , CONFIG_HLP_DLBW_PHYTEST,0, uptr:&target_dl_bw, defintval:0, TYPE_UINT, 0}, \ - {"T" , CONFIG_HLP_ULBW_PHYTEST,0, uptr:&target_ul_bw, defintval:0, TYPE_UINT, 0}, \ -@@ -36,6 +37,7 @@ - extern threads_t threads; - extern uint32_t target_dl_mcs; - extern uint32_t target_dl_Nl; -+extern uint32_t target_ul_Nl; - extern uint32_t target_ul_mcs; - extern uint32_t target_dl_bw; - extern uint32_t target_ul_bw; -diff --git a/executables/nr-ue.c b/executables/nr-ue.c -index 60ff40abeb..a23f91b1dd 100644 ---- a/executables/nr-ue.c -+++ b/executables/nr-ue.c -@@ -278,7 +278,7 @@ void processSlotTX(void *arg) { - int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx); - uint8_t gNB_id = 0; - -- LOG_D(PHY,"%d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); -+ LOG_D(PHY,"processSlotTX %d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type); - if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){ - - // trigger L2 to run ue_scheduler thru IF module -@@ -372,7 +372,8 @@ void processSlotRX(void *arg) { - LOG_D(PHY, "Sending Uplink data \n"); - nr_ue_pusch_common_procedures(UE, - proc->nr_slot_tx, -- &UE->frame_parms,1); -+ &UE->frame_parms, -+ UE->frame_parms.nb_antennas_tx); - } - - if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) { -diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c -index ad5ea982c9..57fd284601 100644 ---- a/executables/nr-uesoftmodem.c -+++ b/executables/nr-uesoftmodem.c -@@ -465,8 +465,11 @@ int main( int argc, char **argv ) { - memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE)); - - set_options(CC_id, UE[CC_id]); -- NR_UE_MAC_INST_t *mac = get_mac_inst(0); -- -+ NR_DL_FRAME_PARMS *fp = &UE[CC_id]->frame_parms; -+ NR_UE_MAC_INST_t *mac = get_mac_inst(0); -+ -+ mac->phy_config.config_req.carrier_config.num_tx_ant = fp->nb_antennas_tx; -+ - if (get_softmodem_params()->sa) { - uint16_t nr_band = get_band(downlink_frequency[CC_id][0],uplink_frequency_offset[CC_id][0]); - mac->nr_band = nr_band; -diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h -index 0e923931ad..8b93417cb0 100644 ---- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h -+++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h -@@ -298,9 +298,10 @@ typedef struct - uint8_t qam_mod_order; - uint8_t mcs_index; - uint8_t mcs_table; -- uint8_t transform_precoding; -+ uint8_t transformPrecoder; - uint16_t data_scrambling_id; - uint8_t nrOfLayers; -+ uint8_t Tpmi; - //DMRS - uint16_t ul_dmrs_symb_pos; - uint8_t dmrs_config_type; -diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h -index 9d245446c8..58ff9037ce 100644 ---- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h -+++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h -@@ -1208,9 +1208,10 @@ typedef struct - uint8_t qam_mod_order; - uint8_t mcs_index; - uint8_t mcs_table; -- uint8_t transform_precoding; -+ uint8_t transformPrecoder; - uint16_t data_scrambling_id; - uint8_t nrOfLayers; -+ uint8_t Tpmi; - //DMRS - uint16_t ul_dmrs_symb_pos; - uint8_t dmrs_config_type; -diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c -index 7cb74f8562..473b0900bc 100644 ---- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c -+++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c -@@ -941,9 +941,10 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui - push8(pusch_pdu->qam_mod_order, ppWritePackedMsg, end) && - push8(pusch_pdu->mcs_index, ppWritePackedMsg, end) && - push8(pusch_pdu->mcs_table, ppWritePackedMsg, end) && -- push8(pusch_pdu->transform_precoding, ppWritePackedMsg, end) && -+ push8(pusch_pdu->transformPrecoder, ppWritePackedMsg, end) && - push16(pusch_pdu->data_scrambling_id, ppWritePackedMsg, end) && - push8(pusch_pdu->nrOfLayers, ppWritePackedMsg, end) && -+ push8(pusch_pdu->Tpmi, ppWritePackedMsg, end) && - push16(pusch_pdu->ul_dmrs_symb_pos, ppWritePackedMsg, end) && - push8(pusch_pdu->dmrs_config_type, ppWritePackedMsg, end) && - push16(pusch_pdu->ul_dmrs_scrambling_id, ppWritePackedMsg, end) && -@@ -4445,9 +4446,10 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(void *tlv, uint8_t **ppReadPacked - pull8(ppReadPackedMsg, &pusch_pdu->qam_mod_order, end) && - pull8(ppReadPackedMsg, &pusch_pdu->mcs_index, end) && - pull8(ppReadPackedMsg, &pusch_pdu->mcs_table, end) && -- pull8(ppReadPackedMsg, &pusch_pdu->transform_precoding, end) && -+ pull8(ppReadPackedMsg, &pusch_pdu->transformPrecoder, end) && - pull16(ppReadPackedMsg, &pusch_pdu->data_scrambling_id, end) && - pull8(ppReadPackedMsg, &pusch_pdu->nrOfLayers, end) && -+ pull8(ppReadPackedMsg, &pusch_pdu->Tpmi, end) && - pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_symb_pos, end) && - pull8(ppReadPackedMsg, &pusch_pdu->dmrs_config_type, end) && - pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_scrambling_id, end) && -diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c -index cd4848ea8c..2ac3230215 100644 ---- a/openair1/PHY/INIT/nr_init.c -+++ b/openair1/PHY/INIT/nr_init.c -@@ -276,11 +276,21 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, - pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); - pusch_vars[ULSCH_id]->ul_ch_mag = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); - pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(n_buf*sizeof(int32_t *) ); -- pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(n_buf*sizeof(int32_t*) ); -+ pusch_vars[ULSCH_id]->rho = (int32_t ***)malloc16_clear(Prx*sizeof(int32_t**) ); -+ pusch_vars[ULSCH_id]->llr_layers = (int16_t **)malloc16(max_ul_mimo_layers*sizeof(int32_t *) ); - - for (i=0; irxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); - pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); -+ pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear( NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); -+ -+ for (int j=0; j< max_ul_mimo_layers; j++) -+ { -+ for (int k=0; krho[i][j*max_ul_mimo_layers+k]=(int32_t *)malloc16_clear( sizeof(int32_t) * fp->N_RB_UL*12*7*2 ); -+ } -+ } - } - for (i=0; iul_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); -@@ -293,8 +303,12 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, - pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); -- pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); -- pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) ); -+ pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); -+ } -+ -+ for (i=0; i< max_ul_mimo_layers; i++) -+ { -+ pusch_vars[ULSCH_id]->llr_layers[i] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear - } - pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear - pusch_vars[ULSCH_id]->ul_valid_re_per_slot = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot); -diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c -index 4024ed1617..169db48e69 100644 ---- a/openair1/PHY/INIT/nr_init_ru.c -+++ b/openair1/PHY/INIT/nr_init_ru.c -@@ -41,7 +41,7 @@ int nr_phy_init_RU(RU_t *ru) { - int p; - int re; - -- LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); -+ LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n",ru_if_types[ru->if_south],ru->nb_tx, ru->nb_rx); - - nfapi_nr_config_request_scf_t *cfg; - ru->nb_log_antennas=0; -diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c -index b60e77e814..11fb6e7d61 100644 ---- a/openair1/PHY/INIT/nr_init_ue.c -+++ b/openair1/PHY/INIT/nr_init_ue.c -@@ -124,7 +124,8 @@ void phy_init_nr_ue_PUSCH(NR_UE_PUSCH *const pusch, - AssertFatal( pusch, "pusch==0" ); - - for (int i=0; itxdataF_layers[i] = (int32_t *)malloc16_clear(NR_MAX_PUSCH_ENCODED_LENGTH*sizeof(int32_t)); -+ pusch->txdataF_layers[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); -+ pusch->txdataF_precoding[i] = (int32_t *)malloc16_clear((NR_MAX_PUSCH_ENCODED_LENGTH)*sizeof(int32_t *)); - } - } - -@@ -143,7 +144,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, - uint16_t N_n_scid[2] = {0,1}; // [HOTFIX] This is a temporary implementation of scramblingID0 and scramblingID1 which are given by DMRS-UplinkConfig - int n_scid; - abstraction_flag = 0; -- LOG_I(PHY, "Initializing UE vars (abstraction %u) for gNB TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); -+ LOG_I(PHY, "Initializing UE vars (abstraction %u) for UE TXant %u, UE RXant %u\n", abstraction_flag, fp->nb_antennas_tx, fp->nb_antennas_rx); - //LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_gNB_INST); - phy_init_nr_top(ue); - // many memory allocation sizes are hard coded -diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c -index 1f164748bf..9a432e8615 100644 ---- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c -+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c -@@ -110,7 +110,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, - fr = filt8_r1; - fmm = filt8_mm1; - fml = filt8_ml1; -- fmr = filt8_m1; -+ fmr = filt8_mm1; - fdcl = filt8_dcl1; - fdcr = filt8_dcr1; - fdclh = filt8_dcl1_h; -@@ -129,9 +129,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, - - //------------------generate DMRS------------------// - -- // transform precoding = 1 means disabled -- if (pusch_pdu->transform_precoding == 1) { -- nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, -+ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { -+ nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], (1000+p), 0, nb_rb_pusch, - (pusch_pdu->bwp_start + pusch_pdu->rb_start)*NR_NB_SC_PER_RB, pusch_pdu->dmrs_config_type); - } - else { // if transform precoding or SC-FDMA is enabled in Uplink -@@ -291,7 +290,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, - printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); - #endif -- multadd_real_vector_complex_scalar(fml, -+ multadd_real_vector_complex_scalar(fm, - ch, - ul_ch, - 8); -diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h -index 4fed3a468f..87e4d57362 100644 ---- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h -+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h -@@ -137,21 +137,22 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - @param nb_rb_pusch The number of RBs allocated (used for Resource Allocation Type 1 in NR) - @param frame_parms, Pointer to frame descriptor structure - */ --void nr_ulsch_extract_rbs_single(int32_t **rxdataF, -- NR_gNB_PUSCH *pusch_vars, -- int slot, -- unsigned char symbol, -- uint8_t is_dmrs_symbol, -- nfapi_nr_pusch_pdu_t *pusch_pdu, -- NR_DL_FRAME_PARMS *frame_parms); -+void nr_ulsch_extract_rbs(int32_t **rxdataF, -+ NR_gNB_PUSCH *pusch_vars, -+ int slot, -+ unsigned char symbol, -+ uint8_t is_dmrs_symbol, -+ nfapi_nr_pusch_pdu_t *pusch_pdu, -+ NR_DL_FRAME_PARMS *frame_parms); - - void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext, - NR_DL_FRAME_PARMS *frame_parms, - NR_gNB_ULSCH_t **ulsch_gNB, -- uint8_t symbol, -- uint8_t start_symbol, -- uint16_t nb_rb, -- pusch_dmrs_type_t pusch_dmrs_type); -+ uint8_t symbol, -+ uint8_t is_dmrs_symbol, -+ uint32_t len, -+ uint8_t nrOfLayers, -+ uint16_t nb_rb); - - /** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal - @param ul_ch_estimates_ext Channel estimates in allocated RBs -@@ -185,9 +186,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - int **ul_ch_mag, - int **ul_ch_magb, - int **rxdataF_comp, -- int **rho, -+ int ***rho, - NR_DL_FRAME_PARMS *frame_parms, - unsigned char symbol, -+ int length, - uint8_t is_dmrs_symbol, - unsigned char mod_order, - uint8_t nrOfLayers, -@@ -255,8 +257,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - @param mod_order modulation order - */ - void nr_ulsch_compute_llr(int32_t *rxdataF_comp, -- int32_t **ul_ch_mag, -- int32_t **ul_ch_magb, -+ int32_t *ul_ch_mag, -+ int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_rb, - uint32_t nb_re, -diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c -index 4278338dbc..3ea19a9970 100644 ---- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c -+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c -@@ -137,6 +137,38 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, - #endif - } - -+void nr_ulsch_layer_demapping(int16_t *llr_cw, -+ uint8_t Nl, -+ uint8_t mod_order, -+ uint32_t length, -+ int16_t **llr_layers) -+{ -+ -+ switch (Nl) { -+ -+ case 1: -+ memcpy((void*)llr_cw, (void*)llr_layers[0], (length)*sizeof(int16_t)); -+ break; -+ -+ case 2: -+ case 3: -+ case 4: -+ for (int i=0; i<(length/Nl/mod_order); i++) -+ { -+ for (int l=0; lnumber_of_nr_ulsch_max;i++) { -diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h -index 80c10d74b1..0e660351ae 100644 ---- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h -+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h -@@ -82,6 +82,12 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, - uint32_t Nid, - uint32_t n_RNTI); - -+void nr_ulsch_layer_demapping(int16_t *llr_cw, -+ uint8_t Nl, -+ uint8_t mod_order, -+ uint32_t length, -+ int16_t **llr_layers); -+ - void nr_ulsch_procedures(PHY_VARS_gNB *gNB, - int frame_rx, - int slot_rx, -diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c -index 28dd5ab219..8314c83ad9 100644 ---- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c -+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c -@@ -302,26 +302,27 @@ void nr_idft(int32_t *z, uint32_t Msc_PUSCH) - } - - --void nr_ulsch_extract_rbs_single(int32_t **rxdataF, -- NR_gNB_PUSCH *pusch_vars, -- int slot, -- unsigned char symbol, -- uint8_t is_dmrs_symbol, -- nfapi_nr_pusch_pdu_t *pusch_pdu, -- NR_DL_FRAME_PARMS *frame_parms) -+void nr_ulsch_extract_rbs(int32_t **rxdataF, -+ NR_gNB_PUSCH *pusch_vars, -+ int slot, -+ unsigned char symbol, -+ uint8_t is_dmrs_symbol, -+ nfapi_nr_pusch_pdu_t *pusch_pdu, -+ NR_DL_FRAME_PARMS *frame_parms) - { - - unsigned short start_re, re, nb_re_pusch; -- unsigned char aarx; -+ unsigned char aarx, aatx; - uint32_t rxF_ext_index = 0; - uint32_t ul_ch0_ext_index = 0; - uint32_t ul_ch0_index = 0; -- uint8_t k_prime; -- uint16_t n; -+ //uint8_t k_prime; -+ //uint16_t n; - int16_t *rxF,*rxF_ext; - int *ul_ch0,*ul_ch0_ext; -- uint8_t delta = 0; -+ //uint8_t delta = 0; - int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; -+ - #ifdef DEBUG_RB_EXT - - printf("--------------------symbol = %d-----------------------\n", symbol); -@@ -329,7 +330,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, - - #endif - -- uint8_t is_dmrs_re; -+ uint8_t is_data_re; - start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB)%frame_parms->ofdm_symbol_size; - nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; - #ifdef __AVX2__ -@@ -338,64 +339,95 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, - int nb_re_pusch2 = nb_re_pusch; - #endif - -- for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { -+ for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) -+ { - - rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; - rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 -- -- ul_ch0 = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available -- -- ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch2]; -- -- n = 0; -- k_prime = 0; -- rxF_ext_index = 0; -- ul_ch0_ext_index = 0; -- ul_ch0_index = 0; -- -- if (is_dmrs_symbol == 0) { -+ -+ if (is_dmrs_symbol == 0) -+ { - // - //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); -- if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { -+ if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) -+ { - memcpy1((void*)rxF_ext, - (void*)&rxF[start_re*2], - nb_re_pusch*sizeof(int32_t)); -- } else { -- int neg_length = frame_parms->ofdm_symbol_size-start_re; -- int pos_length = nb_re_pusch-neg_length; -+ } -+ else -+ { -+ int neg_length = frame_parms->ofdm_symbol_size-start_re; -+ int pos_length = nb_re_pusch-neg_length; -+ memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); -+ memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); -+ } - -- memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); -- memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); -+ #ifdef SUPPORT_PMI_MATRIC -+ for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) -+ #else -+ aatx = aarx; -+ #endif -+ { -+ ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available -+ ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; -+ -+ memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); - } -- memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); - } -- else { -- for (re = 0; re < nb_re_pusch; re++) { -- -- is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type)); -- --#ifdef DEBUG_RB_EXT -- printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); --#endif -- -- /* save only data and respective channel estimates */ -- if (is_dmrs_re == 0) { -- rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); -- rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); -- ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; -+ else -+ { -+ #ifdef SUPPORT_PMI_MATRIC -+ for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) -+ #else -+ aatx = aarx; -+ #endif -+ { -+ ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available -+ ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; -+ -+ //n = 0; -+ //k_prime = 0; -+ rxF_ext_index = 0; -+ ul_ch0_ext_index = 0; -+ ul_ch0_index = 0; -+ -+ for (re = 0; re < nb_re_pusch; re++) -+ { -+ uint16_t k= start_re+re; -+ -+ is_data_re = allowed_xlsch_re_in_dmrs_symbol(k, start_re, frame_parms->ofdm_symbol_size, pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type); -+ -+ if (++k >= frame_parms->ofdm_symbol_size) -+ { -+ k -= frame_parms->ofdm_symbol_size; -+ } - --#ifdef DEBUG_RB_EXT -- printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", -+ #ifdef DEBUG_RB_EXT -+ printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); -+ #endif -+ -+ /* save only data and respective channel estimates */ -+ if (is_data_re == 1) -+ { -+ if (aatx == aarx) -+ { -+ rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); -+ rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); -+ rxF_ext_index +=2; -+ } -+ -+ ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; -+ ul_ch0_ext_index++; -+ -+ #ifdef DEBUG_RB_EXT -+ printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", - is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1], - ul_ch0_ext_index, ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0], ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]); --#endif -- ul_ch0_ext_index++; -- rxF_ext_index +=2; -- } else { -- n += k_prime; -- k_prime ^= 1; -+ #endif -+ } -+ ul_ch0_index++; - } -- ul_ch0_index++; - } - } - } -@@ -406,16 +438,19 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, - NR_gNB_ULSCH_t **ulsch_gNB, - uint8_t symbol, - uint8_t is_dmrs_symbol, -- unsigned short nb_rb, -- pusch_dmrs_type_t pusch_dmrs_type) -+ uint32_t len, -+ uint8_t nrOfLayers, -+ unsigned short nb_rb) - { - - #if defined(__x86_64__)||defined(__i386__) - - short rb, ch_amp; -- unsigned char aarx; -+ unsigned char aarx,aatx; - __m128i *ul_ch128, ch_amp128; - -+ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); -+ - // Determine scaling amplitude based the symbol - - ch_amp = 1024*8; //((pilots) ? (ulsch_gNB[0]->sqrt_rho_b) : (ulsch_gNB[0]->sqrt_rho_a)); -@@ -431,35 +466,26 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, - int off = 0; - #endif - -- for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) { -- -- ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; -- -- if (is_dmrs_symbol==1){ -- if (pusch_dmrs_type == pusch_dmrs_type1) -- nb_rb = nb_rb>>1; -- else -- nb_rb = (2*nb_rb)/3; -- } -- -- for (rb=0;rbnb_antennas_rx; aarx++) -+ { -+ ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; - -+ for (rb=0;rb < nb_rb_0;rb++) -+ { - ul_ch128[0] = _mm_mulhi_epi16(ul_ch128[0], ch_amp128); - ul_ch128[0] = _mm_slli_epi16(ul_ch128[0], 3); - - ul_ch128[1] = _mm_mulhi_epi16(ul_ch128[1], ch_amp128); - ul_ch128[1] = _mm_slli_epi16(ul_ch128[1], 3); - -- if (is_dmrs_symbol) { -- ul_ch128+=2; -- } else { -- ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); -- ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); -- ul_ch128+=3; -- -- } -+ ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); -+ ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); -+ ul_ch128+=3; - } -- } -+ } -+} - #endif - } - -@@ -481,6 +507,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - - int16_t x = factor2(len); - int16_t y = (len)>>x; -+ -+ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); - - #ifdef __AVX2__ - int off = ((nb_rb&1) == 1)? 4:0; -@@ -489,13 +517,16 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - #endif - - for (aatx = 0; aatx < nrOfLayers; aatx++) -- for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { -+ { -+ for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) -+ { - //clear average level - avg128U = _mm_setzero_si128(); - - ul_ch128=(__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - -- for (rb = 0; rb < len/12; rb++) { -+ for (rb = 0; rb < nb_rb_0; rb++) -+ { - avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x)); - avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[1], ul_ch128[1]), x)); - avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[2], ul_ch128[2]), x)); -@@ -508,7 +539,8 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - ((int32_t*)&avg128U)[3]) / y; - - } -- -+ } -+ - _mm_empty(); - _m_empty(); - -@@ -520,7 +552,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - int16x4_t *ul_ch128; - - symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; -- -+ uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); - for (aatx=0; aatxnb_antennas_rx; aarx++) { - //clear average level -@@ -529,7 +561,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - - ul_ch128 = (int16x4_t *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*frame_parms->N_RB_UL*12]; - -- for (rb = 0; rb < nb_rb; rb++) { -+ for (rb = 0; rb < nb_rb_0; rb++) { - // printf("rb %d : ",rb); - // print_shorts("ch",&ul_ch128[0]); - avg128U = vqaddq_s32(avg128U, vmull_s16(ul_ch128[0], ul_ch128[0])); -@@ -568,14 +600,20 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, - #endif - } - -+ -+ -+//============================================================================================== -+// Pre-processing for LLR computation -+//============================================================================================== - void nr_ulsch_channel_compensation(int **rxdataF_ext, - int **ul_ch_estimates_ext, - int **ul_ch_mag, - int **ul_ch_magb, - int **rxdataF_comp, -- int **rho, -+ int ***rho, - NR_DL_FRAME_PARMS *frame_parms, - unsigned char symbol, -+ int length, - uint8_t is_dmrs_symbol, - unsigned char mod_order, - uint8_t nrOfLayers, -@@ -637,20 +675,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128={0},QAM_amp128b={0}; - QAM_amp128b = _mm_setzero_si128(); - -- for (aatx=0; aatxnb_antennas_rx; aarx++) { -- -+ for (aarx=0; aarxnb_antennas_rx; aarx++) -+ { - ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - ul_ch_mag128 = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - ul_ch_mag128b = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; -@@ -658,8 +700,10 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - rxdataF_comp128 = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - - -- for (rb=0; rb2) { -+ for (rb=0; rb2) -+ { - // get channel amplitude if not QPSK - - //print_shorts("ch:",(int16_t*)&ul_ch128[0]); -@@ -679,6 +723,8 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - ul_ch_mag128[0] = _mm_mulhi_epi16(ul_ch_mag128[0],QAM_amp128); - ul_ch_mag128[0] = _mm_slli_epi16(ul_ch_mag128[0],1); - -+ ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); -+ ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); - // print_ints("ch: = ",(int32_t*)&mmtmpD0); - // print_shorts("QAM_amp:",(int16_t*)&QAM_amp128); - // print_shorts("mag:",(int16_t*)&ul_ch_mag128[0]); -@@ -687,30 +733,24 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - ul_ch_mag128b[1] = ul_ch_mag128[1]; - ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128); - ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],1); -+ -+ ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128); -+ ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); - -- if (is_dmrs_symbol==0) { -- mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); -- mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); -- mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); -- -- ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); -- ul_ch_mag128b[2] = ul_ch_mag128[2]; -+ mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); -+ mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); -+ mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); - -- ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); -- ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); -- } -+ ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1); -+ ul_ch_mag128b[2] = ul_ch_mag128[2]; - -- ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128b); -- ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],1); -+ ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128); -+ ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],1); - - -- ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128b); -- ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); -+ ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); -+ ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); - -- if (is_dmrs_symbol==0) { -- ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); -- ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); -- } - } - - // multiply by conjugated channel -@@ -755,117 +795,157 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - // print_shorts("ch:",ul_ch128+1); - // print_shorts("pack:",rxdataF_comp128+1); - -- if (is_dmrs_symbol==0) { -- // multiply by conjugated channel -- mmtmpD0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]); -- // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) -- mmtmpD1 = _mm_shufflelo_epi16(ul_ch128[2],_MM_SHUFFLE(2,3,0,1)); -- mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); -- mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate); -- mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[2]); -- // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit) -- mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); -- mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift); -- mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); -- mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); -- -- rxdataF_comp128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3); -- // print_shorts("rx:",rxdataF128+2); -- // print_shorts("ch:",ul_ch128+2); -- // print_shorts("pack:",rxdataF_comp128+2); -- -- ul_ch128+=3; -- ul_ch_mag128+=3; -- ul_ch_mag128b+=3; -- rxdataF128+=3; -- rxdataF_comp128+=3; -- } else { // we have a smaller PUSCH in symbols with pilots so skip last group of 4 REs and increment less -- ul_ch128+=2; -- ul_ch_mag128+=2; -- ul_ch_mag128b+=2; -- rxdataF128+=2; -- rxdataF_comp128+=2; -- } -- -- } -- } -- } -- -- if (rho) { -- -- for (aarx=0; aarxnb_antennas_rx; aarx++) { -- rho128 = (__m128i *)&rho[aarx][symbol*frame_parms->N_RB_UL*12]; -- ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_UL*12]; -- ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_UL*12]; -- -- for (rb=0; rbnb_antennas_rx][nrOfLayers*nrOfLayers]; -+ int avg_rho_im[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; -+ -+ for (aarx=0; aarxnb_antennas_rx; aarx++) -+ { -+ for (aatx=0; aatx < nrOfLayers; aatx++) -+ { -+ ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; -+ -+ for (int atx=0; atx< nrOfLayers; atx++) -+ { -+ avg_rho_re[aarx][aatx*nrOfLayers+atx] = 0; -+ avg_rho_im[aarx][aatx*nrOfLayers+atx] = 0; -+ rho128 = (__m128i *)&rho[aarx][aatx*nrOfLayers+atx][symbol*(off+(nb_rb*12))]; -+ ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[atx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; -+ -+ for (rb=0; rbrx_correlation[0][0][aarx] = signal_energy(&rho[aarx][aatx*nb_aatx+atx][symbol*nb_rb*12],rb*12); -+ avg_rho_re[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_re[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); -+ avg_rho_im[aarx][aatx*nrOfLayers+atx] = 16*avg_rho_im[aarx][aatx*nrOfLayers+atx]/(nb_rb*12); -+ //printf("rho[rx]%d tx%d tx%d = Re: %d Im: %d\n",aarx, aatx,atx, avg_rho_re[aarx][aatx*nb_aatx+atx], avg_rho_im[aarx][aatx*nb_aatx+atx]); -+ } -+ } -+ } - } - } - -@@ -1105,19 +1185,23 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, - } - - void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, -- int32_t **rxdataF_comp, -- int32_t **ul_ch_mag, -- int32_t **ul_ch_magb, -- uint8_t symbol, -- uint16_t nb_rb) { -+ int32_t **rxdataF_comp, -+ int32_t **ul_ch_mag, -+ int32_t **ul_ch_magb, -+ int32_t ***rho, -+ uint8_t nrOfLayers, -+ uint8_t symbol, -+ uint16_t nb_rb, -+ int length) { - int n_rx = frame_parms->nb_antennas_rx; - #if defined(__x86_64__) || defined(__i386__) -- __m128i *rxdataF_comp128[1+n_rx],*ul_ch_mag128[1+n_rx],*ul_ch_mag128b[1+n_rx]; -+ __m128i *rxdataF_comp128[2],*ul_ch_mag128[2],*ul_ch_mag128b[2]; - #elif defined(__arm__) - int16x8_t *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b; - int16x8_t *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b; - #endif - int32_t i; -+ uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); - - #ifdef __AVX2__ - int off = ((nb_rb&1) == 1)? 4:0; -@@ -1125,23 +1209,34 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, - int off = 0; - #endif - -- if (frame_parms->nb_antennas_rx>1) { --#if defined(__x86_64__) || defined(__i386__) -- int nb_re = nb_rb*12; -- for (int aa=0;aanb_antennas_rx;aa++) { -- rxdataF_comp128[aa] = (__m128i *)&rxdataF_comp[aa][(symbol*(nb_re + off))]; -- ul_ch_mag128[aa] = (__m128i *)&ul_ch_mag[aa][(symbol*(nb_re + off))]; -- ul_ch_mag128b[aa] = (__m128i *)&ul_ch_magb[aa][(symbol*(nb_re + off))]; -- } -- for (int aa=1;aanb_antennas_rx;aa++) { -- // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) -- for (i=0; i 1) -+ { -+ #if defined(__x86_64__) || defined(__i386__) -+ for (int aatx=0; aatxnb_antennas_rx][(symbol*(nb_re + off))]; -+ ul_ch_mag128[0] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; -+ ul_ch_mag128b[0] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; -+ -+ for (int aa=1;aa < n_rx;aa++) -+ { -+ rxdataF_comp128[1] = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; -+ ul_ch_mag128[1] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; -+ ul_ch_mag128b[1] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; -+ -+ // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) -+ for (i=0; iN_RB_DL*12]; - rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12]; - ul_ch_mag128_0 = (int16x8_t *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12]; -@@ -1156,7 +1251,7 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, - ul_ch_mag128_0b[i] = vhaddq_s16(ul_ch_mag128_0b[i],ul_ch_mag128_1b[i]); - rxdataF_comp128_0[i] = vqaddq_s16(rxdataF_comp128_0[i],(*(int16x8_t *)&jitterc[0])); - } --#endif -+ #endif - } - - #if defined(__x86_64__) || defined(__i386__) -@@ -1165,6 +1260,696 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, - #endif - } - -+/* Zero Forcing Rx function: nr_det_HhH() -+ * -+ * -+ * */ -+void nr_ulsch_det_HhH(int32_t *after_mf_00,//a -+ int32_t *after_mf_01,//b -+ int32_t *after_mf_10,//c -+ int32_t *after_mf_11,//d -+ int32_t *det_fin,//1/ad-bc -+ unsigned short nb_rb, -+ unsigned char symbol, -+ int32_t shift) -+{ -+ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; -+ unsigned short rb; -+ __m128i *after_mf_00_128,*after_mf_01_128, *after_mf_10_128, *after_mf_11_128, ad_re_128, bc_re_128; //ad_im_128, bc_im_128; -+ __m128i *det_fin_128, det_re_128; //det_im_128, tmp_det0, tmp_det1; -+ -+ after_mf_00_128 = (__m128i *)after_mf_00; -+ after_mf_01_128 = (__m128i *)after_mf_01; -+ after_mf_10_128 = (__m128i *)after_mf_10; -+ after_mf_11_128 = (__m128i *)after_mf_11; -+ -+ det_fin_128 = (__m128i *)det_fin; -+ -+ for (rb=0; rb<3*nb_rb; rb++) { -+ -+ //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) -+ //The imag part is often zero, we compute only the real part -+ ad_re_128 = _mm_sign_epi16(after_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); -+ ad_re_128 = _mm_madd_epi16(ad_re_128,after_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 -+ //ad_im_128 = _mm_shufflelo_epi16(after_mf_00_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ //ad_im_128 = _mm_shufflehi_epi16(ad_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ //ad_im_128 = _mm_madd_epi16(ad_im_128,after_mf_11_128[0]);//Im: (Q_aI_d + I_aQ_d) -+ -+ //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) -+ //The imag part is often zero, we compute only the real part -+ bc_re_128 = _mm_sign_epi16(after_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); -+ bc_re_128 = _mm_madd_epi16(bc_re_128,after_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 -+ //bc_im_128 = _mm_shufflelo_epi16(after_mf_01_128[0],_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits -+ //bc_im_128 = _mm_shufflehi_epi16(bc_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_b0 Q_b1 I_b2 Q_b3]_64bits to [Q_b1 I_b0 Q_b3 I_b2]_64bits -+ //bc_im_128 = _mm_madd_epi16(bc_im_128,after_mf_10_128[0]);//Im: (Q_bI_c + I_bQ_c) -+ -+ det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); -+ //det_im_128 = _mm_sub_epi32(ad_im_128, bc_im_128); -+ -+ //det in Q30 format -+ det_fin_128[0] = _mm_abs_epi32(det_re_128); -+ -+ -+#ifdef DEBUG_DLSCH_DEMOD -+ printf("\n Computing det_HhH_inv \n"); -+ //print_ints("det_re_128:",(int32_t*)&det_re_128); -+ //print_ints("det_im_128:",(int32_t*)&det_im_128); -+ print_ints("det_fin_128:",(int32_t*)&det_fin_128[0]); -+#endif -+ det_fin_128+=1; -+ after_mf_00_128+=1; -+ after_mf_01_128+=1; -+ after_mf_10_128+=1; -+ after_mf_11_128+=1; -+ } -+ _mm_empty(); -+ _m_empty(); -+} -+ -+/* Zero Forcing Rx function: nr_inv_comp_muli -+ * Complex number multi: z = x*y -+ * = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) -+ * */ -+__m128i nr_ulsch_inv_comp_muli(__m128i input_x, -+ __m128i input_y) -+{ -+ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; -+ -+ __m128i xy_re_128, xy_im_128; -+ __m128i output_z, tmp_z0, tmp_z1; -+ -+ // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) -+ -+ // the real part -+ xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); -+ xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) -+ -+ // the imag part -+ xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) -+ -+ //convert back to Q15 before packing -+ xy_re_128 = _mm_srai_epi32(xy_re_128,4);//(2^15/64*2*16) -+ xy_im_128 = _mm_srai_epi32(xy_im_128,4); -+ -+ tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); -+ //print_ints("unpack lo:",&tmp_z0[0]); -+ tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); -+ //print_ints("unpack hi:",&tmp_z1[0]); -+ output_z = _mm_packs_epi32(tmp_z0,tmp_z1); -+ -+ _mm_empty(); -+ _m_empty(); -+ return(output_z); -+} -+ -+/* Zero Forcing Rx function: nr_conjch0_mult_ch1() -+ * -+ * -+ * */ -+void nr_ulsch_conjch0_mult_ch1(int *ch0, -+ int *ch1, -+ int32_t *ch0conj_ch1, -+ unsigned short nb_rb, -+ unsigned char output_shift0) -+{ -+ //This function is used to compute multiplications in H_hermitian * H matrix -+ short nr_conjugate[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1}; -+ unsigned short rb; -+ __m128i *dl_ch0_128,*dl_ch1_128, *ch0conj_ch1_128, mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; -+ -+ dl_ch0_128 = (__m128i *)ch0; -+ dl_ch1_128 = (__m128i *)ch1; -+ -+ ch0conj_ch1_128 = (__m128i *)ch0conj_ch1; -+ -+ for (rb=0; rb<3*nb_rb; rb++) { -+ -+ mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0],dl_ch1_128[0]); -+ mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[0],_MM_SHUFFLE(2,3,0,1)); -+ mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1)); -+ mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&nr_conjugate[0]); -+ mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch1_128[0]); -+ mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift0); -+ mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift0); -+ mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1); -+ mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1); -+ -+ ch0conj_ch1_128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3); -+ -+ /*printf("\n Computing conjugates \n"); -+ print_shorts("ch0:",(int16_t*)&dl_ch0_128[0]); -+ print_shorts("ch1:",(int16_t*)&dl_ch1_128[0]); -+ print_shorts("pack:",(int16_t*)&ch0conj_ch1_128[0]);*/ -+ -+ dl_ch0_128+=1; -+ dl_ch1_128+=1; -+ ch0conj_ch1_128+=1; -+ } -+ _mm_empty(); -+ _m_empty(); -+} -+__m128i nr_ulsch_comp_muli_sum(__m128i input_x, -+ __m128i input_y, -+ __m128i input_w, -+ __m128i input_z, -+ __m128i det) -+{ -+ int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; -+ -+ __m128i xy_re_128, xy_im_128, wz_re_128, wz_im_128; -+ __m128i output, tmp_z0, tmp_z1; -+ -+ // complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im) -+ // the real part -+ xy_re_128 = _mm_sign_epi16(input_x,*(__m128i*)&nr_conjug2[0]); -+ xy_re_128 = _mm_madd_epi16(xy_re_128,input_y); //Re: (x_re*y_re - x_im*y_im) -+ -+ // the imag part -+ xy_im_128 = _mm_shufflelo_epi16(input_x,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ xy_im_128 = _mm_shufflehi_epi16(xy_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ xy_im_128 = _mm_madd_epi16(xy_im_128,input_y);//Im: (x_im*y_re + x_re*y_im) -+ -+ // complex multiplication (w_re + jw_im)*(z_re + jz_im) = (w_re*z_re - w_im*z_im) + j(w_im*z_re + w_re*z_im) -+ // the real part -+ wz_re_128 = _mm_sign_epi16(input_w,*(__m128i*)&nr_conjug2[0]); -+ wz_re_128 = _mm_madd_epi16(wz_re_128,input_z); //Re: (w_re*z_re - w_im*z_im) -+ -+ // the imag part -+ wz_im_128 = _mm_shufflelo_epi16(input_w,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the low 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ wz_im_128 = _mm_shufflehi_epi16(wz_im_128,_MM_SHUFFLE(2,3,0,1));//permutes IQs for the high 64 bits as [I_a0 Q_a1 I_a2 Q_a3]_64bits to [Q_a1 I_a0 Q_a3 I_a2]_64bits -+ wz_im_128 = _mm_madd_epi16(wz_im_128,input_z);//Im: (w_im*z_re + w_re*z_im) -+ -+ -+ xy_re_128 = _mm_sub_epi32(xy_re_128, wz_re_128); -+ xy_im_128 = _mm_sub_epi32(xy_im_128, wz_im_128); -+ //print_ints("rx_re:",(int32_t*)&xy_re_128[0]); -+ //print_ints("rx_Img:",(int32_t*)&xy_im_128[0]); -+ //divide by matrix det and convert back to Q15 before packing -+ int sum_det =0; -+ for (int k=0; k<4;k++) { -+ sum_det += ((((int *)&det[0])[k])>>2); -+ //printf("det_%d = %d log2 =%d \n",k,(((int *)&det[0])[k]),log2_approx(((int *)&det[0])[k])); -+ } -+ -+ xy_re_128 = _mm_slli_epi32(xy_re_128,5); -+ xy_re_128 = _mm_srai_epi32(xy_re_128,log2_approx(sum_det)); -+ xy_re_128 = _mm_slli_epi32(xy_re_128,5); -+ -+ xy_im_128 = _mm_slli_epi32(xy_im_128,5); -+ xy_im_128 = _mm_srai_epi32(xy_im_128,log2_approx(sum_det)); -+ xy_im_128 = _mm_slli_epi32(xy_im_128,5); -+ -+ tmp_z0 = _mm_unpacklo_epi32(xy_re_128,xy_im_128); -+ //print_ints("unpack lo:",&tmp_z0[0]); -+ tmp_z1 = _mm_unpackhi_epi32(xy_re_128,xy_im_128); -+ //print_ints("unpack hi:",&tmp_z1[0]); -+ output = _mm_packs_epi32(tmp_z0,tmp_z1); -+ -+ _mm_empty(); -+ _m_empty(); -+ return(output); -+} -+/* Zero Forcing Rx function: nr_construct_HhH_elements() -+ * -+ * -+ * */ -+void nr_ulsch_construct_HhH_elements(int *conjch00_ch00, -+ int *conjch01_ch01, -+ int *conjch11_ch11, -+ int *conjch10_ch10,// -+ int *conjch20_ch20, -+ int *conjch21_ch21, -+ int *conjch30_ch30, -+ int *conjch31_ch31, -+ int *conjch00_ch01,//00_01 -+ int *conjch01_ch00,//01_00 -+ int *conjch10_ch11,//10_11 -+ int *conjch11_ch10,//11_10 -+ int *conjch20_ch21, -+ int *conjch21_ch20, -+ int *conjch30_ch31, -+ int *conjch31_ch30, -+ int32_t *after_mf_00, -+ int32_t *after_mf_01, -+ int32_t *after_mf_10, -+ int32_t *after_mf_11, -+ unsigned short nb_rb, -+ unsigned char symbol) -+{ -+ //This function is used to construct the (H_hermitian * H matrix) matrix elements -+ unsigned short rb; -+ __m128i *conjch00_ch00_128, *conjch01_ch01_128, *conjch11_ch11_128, *conjch10_ch10_128; -+ __m128i *conjch20_ch20_128, *conjch21_ch21_128, *conjch30_ch30_128, *conjch31_ch31_128; -+ __m128i *conjch00_ch01_128, *conjch01_ch00_128, *conjch10_ch11_128, *conjch11_ch10_128; -+ __m128i *conjch20_ch21_128, *conjch21_ch20_128, *conjch30_ch31_128, *conjch31_ch30_128; -+ __m128i *after_mf_00_128, *after_mf_01_128, *after_mf_10_128, *after_mf_11_128; -+ -+ conjch00_ch00_128 = (__m128i *)conjch00_ch00; -+ conjch01_ch01_128 = (__m128i *)conjch01_ch01; -+ conjch11_ch11_128 = (__m128i *)conjch11_ch11; -+ conjch10_ch10_128 = (__m128i *)conjch10_ch10; -+ -+ conjch20_ch20_128 = (__m128i *)conjch20_ch20; -+ conjch21_ch21_128 = (__m128i *)conjch21_ch21; -+ conjch30_ch30_128 = (__m128i *)conjch30_ch30; -+ conjch31_ch31_128 = (__m128i *)conjch31_ch31; -+ -+ conjch00_ch01_128 = (__m128i *)conjch00_ch01; -+ conjch01_ch00_128 = (__m128i *)conjch01_ch00; -+ conjch10_ch11_128 = (__m128i *)conjch10_ch11; -+ conjch11_ch10_128 = (__m128i *)conjch11_ch10; -+ -+ conjch20_ch21_128 = (__m128i *)conjch20_ch21; -+ conjch21_ch20_128 = (__m128i *)conjch21_ch20; -+ conjch30_ch31_128 = (__m128i *)conjch30_ch31; -+ conjch31_ch30_128 = (__m128i *)conjch31_ch30; -+ -+ after_mf_00_128 = (__m128i *)after_mf_00; -+ after_mf_01_128 = (__m128i *)after_mf_01; -+ after_mf_10_128 = (__m128i *)after_mf_10; -+ after_mf_11_128 = (__m128i *)after_mf_11; -+ -+ for (rb=0; rb<3*nb_rb; rb++) { -+ -+ after_mf_00_128[0] =_mm_adds_epi16(conjch00_ch00_128[0],conjch10_ch10_128[0]);//00_00 + 10_10 -+ if (conjch20_ch20 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch20_ch20_128[0]); -+ if (conjch30_ch30 != NULL) after_mf_00_128[0] =_mm_adds_epi16(after_mf_00_128[0],conjch30_ch30_128[0]); -+ -+ after_mf_11_128[0] =_mm_adds_epi16(conjch01_ch01_128[0], conjch11_ch11_128[0]); //01_01 + 11_11 -+ if (conjch21_ch21 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch21_ch21_128[0]); -+ if (conjch31_ch31 != NULL) after_mf_11_128[0] =_mm_adds_epi16(after_mf_11_128[0],conjch31_ch31_128[0]); -+ -+ after_mf_01_128[0] =_mm_adds_epi16(conjch00_ch01_128[0], conjch10_ch11_128[0]);//00_01 + 10_11 -+ if (conjch20_ch21 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch20_ch21_128[0]); -+ if (conjch30_ch31 != NULL) after_mf_01_128[0] =_mm_adds_epi16(after_mf_01_128[0],conjch30_ch31_128[0]); -+ -+ after_mf_10_128[0] =_mm_adds_epi16(conjch01_ch00_128[0], conjch11_ch10_128[0]);//01_00 + 11_10 -+ if (conjch21_ch20 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch21_ch20_128[0]); -+ if (conjch31_ch30 != NULL) after_mf_10_128[0] =_mm_adds_epi16(after_mf_10_128[0],conjch31_ch30_128[0]); -+ -+#ifdef DEBUG_DLSCH_DEMOD -+ if ((rb<=30)) -+ { -+ printf(" \n construct_HhH_elements \n"); -+ print_shorts("after_mf_00_128:",(int16_t*)&after_mf_00_128[0]); -+ print_shorts("after_mf_01_128:",(int16_t*)&after_mf_01_128[0]); -+ print_shorts("after_mf_10_128:",(int16_t*)&after_mf_10_128[0]); -+ print_shorts("after_mf_11_128:",(int16_t*)&after_mf_11_128[0]); -+ } -+#endif -+ conjch00_ch00_128+=1; -+ conjch10_ch10_128+=1; -+ conjch01_ch01_128+=1; -+ conjch11_ch11_128+=1; -+ -+ if (conjch20_ch20 != NULL) conjch20_ch20_128+=1; -+ if (conjch21_ch21 != NULL) conjch21_ch21_128+=1; -+ if (conjch30_ch30 != NULL) conjch30_ch30_128+=1; -+ if (conjch31_ch31 != NULL) conjch31_ch31_128+=1; -+ -+ conjch00_ch01_128+=1; -+ conjch01_ch00_128+=1; -+ conjch10_ch11_128+=1; -+ conjch11_ch10_128+=1; -+ -+ if (conjch20_ch21 != NULL) conjch20_ch21_128+=1; -+ if (conjch21_ch20 != NULL) conjch21_ch20_128+=1; -+ if (conjch30_ch31 != NULL) conjch30_ch31_128+=1; -+ if (conjch31_ch30 != NULL) conjch31_ch30_128+=1; -+ -+ after_mf_00_128 += 1; -+ after_mf_01_128 += 1; -+ after_mf_10_128 += 1; -+ after_mf_11_128 += 1; -+ } -+ _mm_empty(); -+ _m_empty(); -+} -+ -+/* Zero Forcing Rx function: nr_ulsch_zero_forcing_rx_2layers() -+ * -+ * -+ * */ -+uint8_t nr_ulsch_zero_forcing_rx_2layers(int **rxdataF_comp, -+ int **ul_ch_mag, -+ int **ul_ch_magb, -+ int **ul_ch_estimates_ext, -+ unsigned short nb_rb, -+ unsigned char n_rx, -+ unsigned char mod_order, -+ int shift, -+ unsigned char symbol, -+ int length) -+{ -+ int *ch00, *ch01, *ch10, *ch11; -+ int *ch20, *ch30, *ch21, *ch31; -+ uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); -+ -+ #ifdef __AVX2__ -+ int off = ((nb_rb&1) == 1)? 4:0; -+ #else -+ int off = 0; -+ #endif -+ -+ /* we need at least alignment to 16 bytes, let's put 32 to be sure -+ * (maybe not necessary but doesn't hurt) -+ */ -+ int32_t conjch00_ch01[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch01_ch00[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch10_ch11[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch11_ch10[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch00_ch00[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch01_ch01[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch10_ch10[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch11_ch11[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch20_ch20[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch21_ch21[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch30_ch30[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch31_ch31[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch20_ch21[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch30_ch31[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch21_ch20[12*nb_rb] __attribute__((aligned(32))); -+ int32_t conjch31_ch30[12*nb_rb] __attribute__((aligned(32))); -+ -+ int32_t af_mf_00[12*nb_rb] __attribute__((aligned(32))); -+ int32_t af_mf_01[12*nb_rb] __attribute__((aligned(32))); -+ int32_t af_mf_10[12*nb_rb] __attribute__((aligned(32))); -+ int32_t af_mf_11[12*nb_rb] __attribute__((aligned(32))); -+ int32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); -+ -+ switch (n_rx) { -+ case 2:// -+ ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; -+ ch01 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; -+ ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; -+ ch11 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; -+ ch20 = NULL; -+ ch21 = NULL; -+ ch30 = NULL; -+ ch31 = NULL; -+ break; -+ -+ case 4:// -+ ch00 = (int *)&ul_ch_estimates_ext[0][symbol*(off+nb_rb*12)]; -+ ch01 = (int *)&ul_ch_estimates_ext[4][symbol*(off+nb_rb*12)]; -+ ch10 = (int *)&ul_ch_estimates_ext[1][symbol*(off+nb_rb*12)]; -+ ch11 = (int *)&ul_ch_estimates_ext[5][symbol*(off+nb_rb*12)]; -+ ch20 = (int *)&ul_ch_estimates_ext[2][symbol*(off+nb_rb*12)]; -+ ch21 = (int *)&ul_ch_estimates_ext[6][symbol*(off+nb_rb*12)]; -+ ch30 = (int *)&ul_ch_estimates_ext[3][symbol*(off+nb_rb*12)]; -+ ch31 = (int *)&ul_ch_estimates_ext[7][symbol*(off+nb_rb*12)]; -+ break; -+ -+ default: -+ return -1; -+ break; -+ } -+ -+ /* 1- Compute the rx channel matrix after compensation: (1/2^log2_max)x(H_herm x H) -+ * for n_rx = 2 -+ * |conj_H_00 conj_H_10| | H_00 H_01| |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| -+ * | | x | | = | | -+ * |conj_H_01 conj_H_11| | H_10 H_11| |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| -+ * -+ */ -+ -+ if (n_rx>=2){ -+ // (1/2^log2_maxh)*conj_H_00xH_00: (1/(64*2))conjH_00*H_00*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch00, -+ ch00, -+ conjch00_ch00, -+ nb_rb_0, -+ shift); -+ // (1/2^log2_maxh)*conj_H_10xH_10: (1/(64*2))conjH_10*H_10*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch10, -+ ch10, -+ conjch10_ch10, -+ nb_rb_0, -+ shift); -+ // conj_H_00xH_01 -+ nr_ulsch_conjch0_mult_ch1(ch00, -+ ch01, -+ conjch00_ch01, -+ nb_rb_0, -+ shift); // this shift is equal to the channel level log2_maxh -+ // conj_H_10xH_11 -+ nr_ulsch_conjch0_mult_ch1(ch10, -+ ch11, -+ conjch10_ch11, -+ nb_rb_0, -+ shift); -+ // conj_H_01xH_01 -+ nr_ulsch_conjch0_mult_ch1(ch01, -+ ch01, -+ conjch01_ch01, -+ nb_rb_0, -+ shift); -+ // conj_H_11xH_11 -+ nr_ulsch_conjch0_mult_ch1(ch11, -+ ch11, -+ conjch11_ch11, -+ nb_rb_0, -+ shift); -+ // conj_H_01xH_00 -+ nr_ulsch_conjch0_mult_ch1(ch01, -+ ch00, -+ conjch01_ch00, -+ nb_rb_0, -+ shift); -+ // conj_H_11xH_10 -+ nr_ulsch_conjch0_mult_ch1(ch11, -+ ch10, -+ conjch11_ch10, -+ nb_rb_0, -+ shift); -+ } -+ if (n_rx==4){ -+ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2*16))conjH_20*H_20*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch20, -+ ch20, -+ conjch20_ch20, -+ nb_rb_0, -+ shift); -+ -+ // (1/2^log2_maxh)*conj_H_30xH_30: (1/(64*2*4))conjH_30*H_30*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch30, -+ ch30, -+ conjch30_ch30, -+ nb_rb_0, -+ shift); -+ -+ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch20, -+ ch21, -+ conjch20_ch21, -+ nb_rb_0, -+ shift); -+ -+ nr_ulsch_conjch0_mult_ch1(ch30, -+ ch31, -+ conjch30_ch31, -+ nb_rb_0, -+ shift); -+ -+ nr_ulsch_conjch0_mult_ch1(ch21, -+ ch21, -+ conjch21_ch21, -+ nb_rb_0, -+ shift); -+ -+ nr_ulsch_conjch0_mult_ch1(ch31, -+ ch31, -+ conjch31_ch31, -+ nb_rb_0, -+ shift); -+ -+ // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15 -+ nr_ulsch_conjch0_mult_ch1(ch21, -+ ch20, -+ conjch21_ch20, -+ nb_rb_0, -+ shift); -+ -+ nr_ulsch_conjch0_mult_ch1(ch31, -+ ch30, -+ conjch31_ch30, -+ nb_rb_0, -+ shift); -+ -+ nr_ulsch_construct_HhH_elements(conjch00_ch00, -+ conjch01_ch01, -+ conjch11_ch11, -+ conjch10_ch10,// -+ conjch20_ch20, -+ conjch21_ch21, -+ conjch30_ch30, -+ conjch31_ch31, -+ conjch00_ch01, -+ conjch01_ch00, -+ conjch10_ch11, -+ conjch11_ch10,// -+ conjch20_ch21, -+ conjch21_ch20, -+ conjch30_ch31, -+ conjch31_ch30, -+ af_mf_00, -+ af_mf_01, -+ af_mf_10, -+ af_mf_11, -+ nb_rb_0, -+ symbol); -+ } -+ if (n_rx==2){ -+ nr_ulsch_construct_HhH_elements(conjch00_ch00, -+ conjch01_ch01, -+ conjch11_ch11, -+ conjch10_ch10,// -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ conjch00_ch01, -+ conjch01_ch00, -+ conjch10_ch11, -+ conjch11_ch10,// -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ af_mf_00, -+ af_mf_01, -+ af_mf_10, -+ af_mf_11, -+ nb_rb_0, -+ symbol); -+ } -+ //det_HhH = ad -bc -+ nr_ulsch_det_HhH(af_mf_00,//a -+ af_mf_01,//b -+ af_mf_10,//c -+ af_mf_11,//d -+ determ_fin, -+ nb_rb_0, -+ symbol, -+ shift); -+ /* 2- Compute the channel matrix inversion ********************************** -+ * -+ * |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)| -+ * A= | | -+ * |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)| -+ * -+ * -+ * -+ *inv(A) =(1/det)*[d -b -+ * -c a] -+ * -+ * -+ **************************************************************************/ -+ __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*ul_ch_mag128_0=NULL,*ul_ch_mag128b_0=NULL,*determ_fin_128;//*dl_ch_mag128_1,*dl_ch_mag128b_1,*dl_ch_mag128r_1 -+ __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3; -+ __m128i *after_mf_a_128,*after_mf_b_128, *after_mf_c_128, *after_mf_d_128; -+ __m128i QAM_amp128={0},QAM_amp128b={0}; -+ -+ determ_fin_128 = (__m128i *)&determ_fin[0]; -+ -+ rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[0][symbol*(off+nb_rb*12)];//aatx=0 @ aarx =0 -+ rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[n_rx][symbol*(off+nb_rb*12)];//aatx=1 @ aarx =0 -+ -+ after_mf_a_128 = (__m128i *)af_mf_00; -+ after_mf_b_128 = (__m128i *)af_mf_01; -+ after_mf_c_128 = (__m128i *)af_mf_10; -+ after_mf_d_128 = (__m128i *)af_mf_11; -+ -+ if (mod_order>2) { -+ if (mod_order == 4) { -+ QAM_amp128 = _mm_set1_epi16(QAM16_n1); //2/sqrt(10) -+ QAM_amp128b = _mm_setzero_si128(); -+ } else if (mod_order == 6) { -+ QAM_amp128 = _mm_set1_epi16(QAM64_n1); //4/sqrt{42} -+ QAM_amp128b = _mm_set1_epi16(QAM64_n2); //2/sqrt{42} -+ } -+ ul_ch_mag128_0 = (__m128i *)&ul_ch_mag[0][symbol*(off+nb_rb*12)]; -+ ul_ch_mag128b_0 = (__m128i *)&ul_ch_magb[0][symbol*(off+nb_rb*12)]; -+ } -+ -+ for (int rb=0; rb<3*nb_rb_0; rb++) { -+ if (mod_order>2) { -+ int sum_det =0; -+ for (int k=0; k<4;k++) { -+ sum_det += ((((int *)&determ_fin_128[0])[k])>>2); -+ //printf("det_%d = %d\n",k,sum_det); -+ } -+ -+ mmtmpD2 = _mm_slli_epi32(determ_fin_128[0],5); -+ mmtmpD2 = _mm_srai_epi32(mmtmpD2,log2_approx(sum_det)); -+ mmtmpD2 = _mm_slli_epi32(mmtmpD2,5); -+ -+ mmtmpD3 = _mm_unpacklo_epi32(mmtmpD2,mmtmpD2); -+ -+ mmtmpD2 = _mm_unpackhi_epi32(mmtmpD2,mmtmpD2); -+ -+ mmtmpD2 = _mm_packs_epi32(mmtmpD3,mmtmpD2); -+ -+ ul_ch_mag128_0[0] = mmtmpD2; -+ ul_ch_mag128b_0[0] = mmtmpD2; -+ -+ ul_ch_mag128_0[0] = _mm_mulhi_epi16(ul_ch_mag128_0[0],QAM_amp128); -+ ul_ch_mag128_0[0] = _mm_slli_epi16(ul_ch_mag128_0[0],1); -+ -+ ul_ch_mag128b_0[0] = _mm_mulhi_epi16(ul_ch_mag128b_0[0],QAM_amp128b); -+ ul_ch_mag128b_0[0] = _mm_slli_epi16(ul_ch_mag128b_0[0],1); -+ -+ //print_shorts("mag layer 1:",(int16_t*)&dl_ch_mag128_0[0]); -+ //print_shorts("mag layer 2:",(int16_t*)&dl_ch_mag128_1[0]); -+ //print_shorts("magb layer 1:",(int16_t*)&dl_ch_mag128b_0[0]); -+ //print_shorts("magb layer 2:",(int16_t*)&dl_ch_mag128b_1[0]); -+ //print_shorts("magr layer 1:",(int16_t*)&dl_ch_mag128r_0[0]); -+ //print_shorts("magr layer 2:",(int16_t*)&dl_ch_mag128r_1[0]); -+ } -+ // multiply by channel Inv -+ //rxdataF_zf128_0 = rxdataF_comp128_0*d - b*rxdataF_comp128_1 -+ //rxdataF_zf128_1 = rxdataF_comp128_1*a - c*rxdataF_comp128_0 -+ //printf("layer_1 \n"); -+ mmtmpD0 = nr_ulsch_comp_muli_sum(rxdataF_comp128_0[0], -+ after_mf_d_128[0], -+ rxdataF_comp128_1[0], -+ after_mf_b_128[0], -+ determ_fin_128[0]); -+ -+ //printf("layer_2 \n"); -+ mmtmpD1 = nr_ulsch_comp_muli_sum(rxdataF_comp128_1[0], -+ after_mf_a_128[0], -+ rxdataF_comp128_0[0], -+ after_mf_c_128[0], -+ determ_fin_128[0]); -+ -+ rxdataF_comp128_0[0] = mmtmpD0; -+ rxdataF_comp128_1[0] = mmtmpD1; -+#ifdef DEBUG_DLSCH_DEMOD -+ printf("\n Rx signal after ZF l%d rb%d\n",symbol,rb); -+ print_shorts(" Rx layer 1:",(int16_t*)&rxdataF_comp128_0[0]); -+ print_shorts(" Rx layer 2:",(int16_t*)&rxdataF_comp128_1[0]); -+#endif -+ determ_fin_128 += 1; -+ ul_ch_mag128_0 += 1; -+ ul_ch_mag128b_0 += 1; -+ rxdataF_comp128_0 += 1; -+ rxdataF_comp128_1 += 1; -+ after_mf_a_128 += 1; -+ after_mf_b_128 += 1; -+ after_mf_c_128 += 1; -+ after_mf_d_128 += 1; -+ } -+ _mm_empty(); -+ _m_empty(); -+ return(0); -+} -+ -+//============================================================================================== -+ -+/* Main Function */ - int nr_rx_pusch(PHY_VARS_gNB *gNB, - uint8_t ulsch_id, - uint32_t frame, -@@ -1184,21 +1969,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - gNB->pusch_vars[ulsch_id]->cl_done = 0; - - bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start)*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; -- LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); -- LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); -- -+ LOG_I(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); -+ LOG_I(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); -+ LOG_I(PHY,"ulsch RX %x : start_rb %d nb_rb %d mcs %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_ports %d\n", -+ rel15_ul->rnti,rel15_ul->rb_start,rel15_ul->rb_size,rel15_ul->mcs_index, -+ rel15_ul->nrOfLayers,0,rel15_ul->bwp_start,0,rel15_ul->start_symbol_index,rel15_ul->nr_of_symbols, -+ rel15_ul->num_dmrs_cdm_grps_no_data,rel15_ul->ul_dmrs_symb_pos,rel15_ul->dmrs_ports); - //---------------------------------------------------------- - //--------------------- Channel estimation --------------------- - //---------------------------------------------------------- - start_meas(&gNB->ulsch_channel_estimation_stats); -- for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { -+ for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) -+ { - uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; - LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag); -- if (dmrs_symbol_flag == 1) { -+ -+ if (dmrs_symbol_flag == 1) -+ { - if (gNB->pusch_vars[ulsch_id]->dmrs_symbol == INVALID_VALUE) - gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; - - for (int nl=0; nlnrOfLayers; nl++) -+ { -+ - nr_pusch_channel_estimation(gNB, - slot, - get_dmrs_port(nl,rel15_ul->dmrs_ports), -@@ -1206,6 +1999,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - ulsch_id, - bwp_start_subcarrier, - rel15_ul); -+ } - - nr_gnb_measurements(gNB, ulsch_id, harq_pid, symbol,rel15_ul->nrOfLayers); - -@@ -1214,9 +2008,12 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] = 0; - gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] = 0; - } -- gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( -- &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aarx][symbol * frame_parms->ofdm_symbol_size], -+ for (aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) -+ { -+ gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( -+ &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aatx*gNB->frame_parms.nb_antennas_rx+aarx][symbol * frame_parms->ofdm_symbol_size], - rel15_ul->rb_size * 12); -+ } - for (int rb = 0; rb < rel15_ul->rb_size; rb++) { - gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] += - gNB->measurements.n0_subband_power[aarx][rel15_ul->bwp_start + rel15_ul->rb_start + rb] / -@@ -1234,23 +2031,29 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - #endif - uint32_t rxdataF_ext_offset = 0; - -- for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { -+ for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) -+ { - uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; -- if (dmrs_symbol_flag == 1) { -+ if (dmrs_symbol_flag == 1) -+ { - if ((rel15_ul->ul_dmrs_symb_pos >> ((symbol + 1) % frame_parms->symbols_per_slot)) & 0x01) - AssertFatal(1==0,"Double DMRS configuration is not yet supported\n"); - - gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; - -- if (rel15_ul->dmrs_config_type == 0) { -+ if (rel15_ul->dmrs_config_type == 0) -+ { - // if no data in dmrs cdm group is 1 only even REs have no data - // if no data in dmrs cdm group is 2 both odd and even REs have no data - nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*6)); - } -- else { -+ else -+ { - nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*4)); - } -- } else { -+ } -+ else -+ { - nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; - } - -@@ -1260,16 +2063,16 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - //---------------------------------------------------------- - //--------------------- RBs extraction --------------------- - //---------------------------------------------------------- -- if (nb_re_pusch > 0) { -- -+ if (nb_re_pusch > 0) -+ { - start_meas(&gNB->ulsch_rbs_extraction_stats); -- nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF, -- gNB->pusch_vars[ulsch_id], -- slot, -- symbol, -- dmrs_symbol_flag, -- rel15_ul, -- frame_parms); -+ nr_ulsch_extract_rbs(gNB->common_vars.rxdataF, -+ gNB->pusch_vars[ulsch_id], -+ slot, -+ symbol, -+ dmrs_symbol_flag, -+ rel15_ul, -+ frame_parms); - stop_meas(&gNB->ulsch_rbs_extraction_stats); - - //---------------------------------------------------------- -@@ -1280,8 +2083,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - gNB->ulsch[ulsch_id], - symbol, - dmrs_symbol_flag, -- rel15_ul->rb_size, -- rel15_ul->dmrs_config_type); -+ nb_re_pusch, -+ rel15_ul->nrOfLayers, -+ rel15_ul->rb_size); - - if (gNB->pusch_vars[ulsch_id]->cl_done==0) { - nr_ulsch_channel_level(gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, -@@ -1312,9 +2116,14 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - gNB->pusch_vars[ulsch_id]->ul_ch_mag0, - gNB->pusch_vars[ulsch_id]->ul_ch_magb0, - gNB->pusch_vars[ulsch_id]->rxdataF_comp, -+ #ifdef SUPPORT_PMI_MATRIC - (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, -+ #else -+ NULL, -+ #endif - frame_parms, - symbol, -+ nb_re_pusch, - dmrs_symbol_flag, - rel15_ul->qam_mod_order, - rel15_ul->nrOfLayers, -@@ -1327,19 +2136,37 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - gNB->pusch_vars[ulsch_id]->rxdataF_comp, - gNB->pusch_vars[ulsch_id]->ul_ch_mag0, - gNB->pusch_vars[ulsch_id]->ul_ch_magb0, -+ #ifdef SUPPORT_PMI_MATRIC -+ (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, -+ #else -+ NULL, -+ #endif -+ rel15_ul->nrOfLayers, - symbol, -- rel15_ul->rb_size); -+ rel15_ul->rb_size, -+ nb_re_pusch); -+ -+ if (rel15_ul->nrOfLayers == 2)//Apply zero forcing for 2 Tx layers -+ nr_ulsch_zero_forcing_rx_2layers(gNB->pusch_vars[ulsch_id]->rxdataF_comp, -+ gNB->pusch_vars[ulsch_id]->ul_ch_mag0, -+ gNB->pusch_vars[ulsch_id]->ul_ch_magb0, -+ gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, -+ rel15_ul->rb_size, -+ frame_parms->nb_antennas_rx, -+ rel15_ul->qam_mod_order, -+ gNB->pusch_vars[ulsch_id]->log2_maxh, -+ symbol, -+ nb_re_pusch); - stop_meas(&gNB->ulsch_mrc_stats); - -- // transform precoding = 0 means enabled -- if (rel15_ul->transform_precoding == 0) { -- -- #ifdef __AVX2__ -+ if (rel15_ul->transformPrecoder == transformPrecoder_enabled) -+ { -+ #ifdef __AVX2__ - // For odd number of resource blocks need byte alignment to multiple of 8 - int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); -- #else -+ #else - int nb_re_pusch2 = nb_re_pusch; -- #endif -+ #endif - - // perform IDFT operation on the compensated rxdata if transform precoding is enabled - nr_idft(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * nb_re_pusch2], nb_re_pusch); -@@ -1351,7 +2178,8 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - //---------------------------------------------------------- - /* In case PTRS is enabled then LLR will be calculated after PTRS symbols are processed * - * otherwise LLR are calculated for each symbol based upon DMRS channel estimates only. */ -- if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { -+ if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) -+ { - start_meas(&gNB->ulsch_ptrs_processing_stats); - nr_pusch_ptrs_processing(gNB, - frame_parms, -@@ -1370,14 +2198,17 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, - /*-------------------- LLRs computation -------------------------------------------------------------*/ - /*-----------------------------------------------------------------------------------------------------*/ - start_meas(&gNB->ulsch_llr_stats); -- nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], -- gNB->pusch_vars[ulsch_id]->ul_ch_mag0, -- gNB->pusch_vars[ulsch_id]->ul_ch_magb0, -- &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order], -- rel15_ul->rb_size, -- gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], -- symbol, -- rel15_ul->qam_mod_order); -+ for (aatx=0; aatx < rel15_ul->nrOfLayers; aatx++) -+ { -+ nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aatx*frame_parms->nb_antennas_rx][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], -+ gNB->pusch_vars[ulsch_id]->ul_ch_mag0[aatx*frame_parms->nb_antennas_rx], -+ gNB->pusch_vars[ulsch_id]->ul_ch_magb0[aatx*frame_parms->nb_antennas_rx], -+ &gNB->pusch_vars[ulsch_id]->llr_layers[aatx][rxdataF_ext_offset * rel15_ul->qam_mod_order], -+ rel15_ul->rb_size, -+ gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol], -+ symbol, -+ rel15_ul->qam_mod_order); -+ } - stop_meas(&gNB->ulsch_llr_stats); - rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol]; - } -diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c -index bf96a76106..ad41ebf3d6 100644 ---- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c -+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c -@@ -64,7 +64,7 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, - //---------------------------------------------------------------------------------------------- - - void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, -- int32_t **ul_ch_mag, -+ int32_t *ul_ch_mag, - int16_t *ulsch_llr, - uint32_t nb_rb, - uint32_t nb_re, -@@ -110,12 +110,12 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, - - #if defined(__x86_64__) || defined(__i386__) - #ifdef __AVX2__ -- ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; -+ ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; - #else -- ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; -+ ch_mag = (__m128i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; - #endif - #elif defined(__arm__) -- ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; -+ ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; - #endif - - #ifdef __AVX2__ -@@ -231,8 +231,8 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, - //---------------------------------------------------------------------------------------------- - - void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, -- int32_t **ul_ch_mag, -- int32_t **ul_ch_magb, -+ int32_t *ul_ch_mag, -+ int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_rb, - uint32_t nb_re, -@@ -265,15 +265,15 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - - #if defined(__x86_64__) || defined(__i386__) - #ifdef __AVX2__ -- ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; -- ch_magb = (__m256i*)&ul_ch_magb[0][(symbol*(off+(nb_rb*12)))]; -+ ch_mag = (__m256i*)&ul_ch_mag[(symbol*(off+(nb_rb*12)))]; -+ ch_magb = (__m256i*)&ul_ch_magb[(symbol*(off+(nb_rb*12)))]; - #else -- ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)]; -- ch_magb = (__m128i*)&ul_ch_magb[0][(symbol*nb_rb*12)]; -+ ch_mag = (__m128i*)&ul_ch_mag[(symbol*nb_rb*12)]; -+ ch_magb = (__m128i*)&ul_ch_magb[(symbol*nb_rb*12)]; - #endif - #elif defined(__arm__) -- ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; -- ch_magb = (int16x8_t*)&ul_ch_magb[0][(symbol*nb_rb*12)]; -+ ch_mag = (int16x8_t*)&ul_ch_mag[(symbol*nb_rb*12)]; -+ ch_magb = (int16x8_t*)&ul_ch_magb[(symbol*nb_rb*12)]; - #endif - - #ifdef __AVX2__ -@@ -471,8 +471,8 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - - - void nr_ulsch_compute_llr(int32_t *rxdataF_comp, -- int32_t **ul_ch_mag, -- int32_t **ul_ch_magb, -+ int32_t *ul_ch_mag, -+ int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_rb, - uint32_t nb_re, -diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c -index 65ae288252..2cb7609d62 100644 ---- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c -+++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c -@@ -148,7 +148,7 @@ short filt8_dcr0_h[8]= { - 0,4096,8192,12288,16384,0,0,0}; - - short filt8_l1[8] = { --24576,16384,0,0,0,0,0,0}; -+24576,16384,8192,0,0,0,0,0}; - - short filt8_ml1[8] = { - -8192,0,8192,16384,8192,0,0,0}; -@@ -163,10 +163,10 @@ short filt8_mm1[8]= { - 0,0,0,0,8192,16384,8192,0}; - - short filt8_dcl1[8]= { --0,0,0,16384,12288,8192,4096,0}; -+0,0,16384,12288,8192,4096,0,0}; - - short filt8_dcr1[8]= { --0,0,0,0,4096,8192,12288,16384}; -+0,0,0,4096,8192,12288,16384,0}; - - short filt8_dcl1_h[8]= { - 0,16384,12288,8192,4096,0,0,0}; -diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c -index 945dc51673..a293eec6d8 100644 ---- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c -+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c -@@ -258,6 +258,15 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, - Ilbrm = 0; - Tbslbrm = 950984; //max tbs - Coderate = 0.0; -+ -+ #if 0 -+ harq_process->a[0] = 0x31; -+ for (int i = 1; i < harq_process->pusch_pdu.pusch_data.tb_size; i++) -+ { -+ harq_process->a[i] = (i&0xff); -+ } -+ #endif -+ - trace_NRpdu(DIRECTION_UPLINK, harq_process->a, harq_process->pusch_pdu.pusch_data.tb_size, 0, WS_C_RNTI, 0, 0, 0,0, 0); - /////////// - ///////////////////////////////////////////////////////////////////////////////////////// -diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c -index 99dc2b658e..5d76e654ba 100644 ---- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c -+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c -@@ -98,13 +98,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - uint8_t thread_id, - int gNB_id) { - -- LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); -+ LOG_I(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); - - uint32_t available_bits; - uint8_t cwd_index, l; - uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; -- int16_t **tx_layers; -- int32_t **txdataF; -+ - int8_t Wf[2], Wt[2], l_prime[2], delta; - uint8_t nb_dmrs_re_per_rb; - int ap, i; -@@ -112,6 +111,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - - NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; - NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id]; -+ int16_t **tx_layers = (int16_t **)pusch_ue->txdataF_layers; -+ int16_t **tx_precoding = (int16_t **)pusch_ue->txdataF_precoding; -+ int32_t **txdataF = UE->common_vars.txdataF; - - uint8_t num_of_codewords = 1; // tmp assumption - int Nid_cell = 0; -@@ -148,9 +150,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - - nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; - -- LOG_D(PHY,"ulsch %x : start_rb %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", -- rnti,start_rb,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); -- -+ LOG_I(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", -+ rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); -+ - // TbD num_of_mod_symbols is set but never used - N_RE_prime = NR_NB_SC_PER_RB*number_of_symbols - nb_dmrs_re_per_rb*number_dmrs_symbols - N_PRB_oh; - harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb*num_of_codewords; -@@ -236,8 +238,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - /////////////////////////ULSCH layer mapping///////////////////////// - /////////// - -- tx_layers = (int16_t **)pusch_ue->txdataF_layers; -- - nr_ue_layer_mapping(UE->ulsch[thread_id][gNB_id], - Nl, - available_bits/mod_order, -@@ -257,7 +257,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - int16_t *dmrs_seq = NULL; - - // if transform precoding is enbaled (value 0) -- if (pusch_pdu->transform_precoding == 0) { -+ if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { - - uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; - uint32_t y_offset = 0; -@@ -315,10 +315,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); - #endif - -- } -- else -- memcpy(ulsch_ue->y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); -- -+ } - - /////////// - //////////////////////////////////////////////////////////////////////// -@@ -328,145 +325,233 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - /////////////////////////ULSCH RE mapping///////////////////////// - /////////// - -- txdataF = UE->common_vars.txdataF; -- -- for (ap=0; ap< Nl; ap++) { -- -- uint8_t k_prime = 0; -- uint16_t m = 0; -- -- -- #ifdef DEBUG_PUSCH_MAPPING -+ for (ap=0; ap< Nl; ap++) -+ { -+ uint8_t k_prime = 0; -+ uint16_t m = 0; -+ -+ #ifdef DEBUG_PUSCH_MAPPING - printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); -- #endif -- -- -- -- // DMRS params for this ap -- get_Wt(Wt, ap, dmrs_type); -- get_Wf(Wf, ap, dmrs_type); -- delta = get_delta(ap, dmrs_type); -- -- for (l=start_symbol; l> l) & 0x01) { -- is_dmrs_sym = 1; -- -- // transform precoding disabled (value 1) -- if (pusch_pdu->transform_precoding == 1){ -- -- if (dmrs_type == pusch_dmrs_type1) -- dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; -- else -- dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; -- -- // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part -- // Perform this on gold sequence, not required when SC FDMA operation is done, -- LOG_D(PHY,"DMRS in symbol %d\n",l); -- nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated -- -- } else { -- dmrs_idx = 0; -- } -- -- -- } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { -- -- AssertFatal(pusch_pdu->transform_precoding == 1, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); -+ #endif - -- if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { -- is_ptrs_sym = 1; -- nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); -+ // DMRS params for this ap -+ get_Wt(Wt, ap, dmrs_type); -+ get_Wf(Wf, ap, dmrs_type); -+ delta = get_delta(ap, dmrs_type); -+ -+ for (l=start_symbol; l> l) & 0x01) -+ { -+ is_dmrs_sym = 1; -+ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) -+ { -+ if (dmrs_type == pusch_dmrs_type1) -+ dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; -+ else -+ dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; -+ -+ // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part -+ // Perform this on gold sequence, not required when SC FDMA operation is done, -+ LOG_D(PHY,"DMRS in symbol %d\n",l); -+ nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated -+ } -+ else -+ { -+ dmrs_idx = 0; -+ } -+ } -+ else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) -+ { -+ AssertFatal(pusch_pdu->transformPrecoder == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); -+ -+ if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) -+ { -+ is_ptrs_sym = 1; -+ nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); -+ } - } -- } - -- for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) { -+ for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) -+ { -+ uint8_t is_dmrs = 0; -+ uint8_t is_ptrs = 0; - -- uint8_t is_dmrs = 0; -- uint8_t is_ptrs = 0; -+ sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - -- sample_offsetF = l*frame_parms->ofdm_symbol_size + k; -- -- if (is_dmrs_sym) { -- if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) -- is_dmrs = 1; -- } else if (is_ptrs_sym) { -+ if (is_dmrs_sym) -+ { -+ if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) -+ is_dmrs = 1; -+ } -+ else if (is_ptrs_sym) -+ { - is_ptrs = is_ptrs_subcarrier(k, -- rnti, -- ap, -- dmrs_type, -- K_ptrs, -- nb_rb, -- pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, -- start_sc, -- frame_parms->ofdm_symbol_size); -- } -- -- if (is_dmrs == 1) { -- // if transform precoding is enabled -- if (pusch_pdu->transform_precoding == 0) { -- -- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; -+ rnti, -+ ap, -+ dmrs_type, -+ K_ptrs, -+ nb_rb, -+ pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, -+ start_sc, -+ frame_parms->ofdm_symbol_size); -+ } -+ -+ if (is_dmrs == 1) -+ { -+ if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; -+ } -+ else -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; -+ } -+ -+ #ifdef DEBUG_PUSCH_MAPPING -+ printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", -+ ap, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); -+ #endif -+ -+ dmrs_idx++; -+ k_prime++; -+ k_prime&=1; -+ n+=(k_prime)?0:1; -+ } -+ else if (is_ptrs == 1) -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; -+ -+ ptrs_idx++; -+ } -+ else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) -+ { -+ if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[ap])[m<<1]; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[ap])[(m<<1) + 1]; -+ } -+ else -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; -+ } -+ -+ #ifdef DEBUG_PUSCH_MAPPING -+ printf("DATA: layer %d\t m %d\t l %d \t k %d \t txdataF: %d %d\n", -+ ap, m, l, k, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); -+ #endif -+ -+ m++; -+ } -+ else -+ { -+ ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = 0; -+ ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = 0; -+ } -+ -+ if (++k >= frame_parms->ofdm_symbol_size) -+ { -+ k -= frame_parms->ofdm_symbol_size; -+ } -+ } //for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) -+ }//for (l=start_symbol; lnb_antennas_tx; ap++) -+ { -+ for (int l=start_symbol; lTpmi; - -- } else { -- -- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; -- -+ if (pmi == 0) {//unitary Precoding -+ if(ap< pusch_pdu->nrOfLayers) -+ memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], -+ (void*)&tx_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)], -+ NR_NB_SC_PER_RB*sizeof(int32_t)); -+ else -+ memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + k], -+ 0, -+ NR_NB_SC_PER_RB*sizeof(int32_t)); -+ -+ k += NR_NB_SC_PER_RB; -+ if (k >= frame_parms->ofdm_symbol_size) { -+ k -= frame_parms->ofdm_symbol_size; -+ } -+ } -+ else -+ { -+ //get the precoding matrix weights: -+ char *W_prec; -+ switch (frame_parms->nb_antennas_tx) -+ { -+ case 1://1 antenna port -+ W_prec = nr_W_1l_2p[pmi][ap]; -+ break; -+ case 2://2 antenna ports -+ if (pusch_pdu->nrOfLayers == 1)//1 layer -+ W_prec = nr_W_1l_2p[pmi][ap]; -+ else//2 layers -+ W_prec = nr_W_2l_2p[pmi][ap]; -+ break; -+ case 4://4 antenna ports -+ if (pusch_pdu->nrOfLayers == 1)//1 layer -+ W_prec = nr_W_1l_4p[pmi][ap]; -+ else if (pusch_pdu->nrOfLayers == 2)//2 layers -+ W_prec = nr_W_2l_4p[pmi][ap]; -+ else if (pusch_pdu->nrOfLayers == 3)//3 layers -+ W_prec = nr_W_3l_4p[pmi][ap]; -+ else//4 layers -+ W_prec = nr_W_4l_4p[pmi][ap]; -+ break; -+ default: -+ LOG_D(PHY,"Precoding 1,2, or 4 antenna ports are currently supported\n"); -+ W_prec = nr_W_1l_2p[pmi][ap]; -+ break; - } - -- #ifdef DEBUG_PUSCH_MAPPING -- printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", -- dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); -- #endif -- -- -- dmrs_idx++; -- k_prime++; -- k_prime&=1; -- n+=(k_prime)?0:1; -- -- } else if (is_ptrs == 1) { -- -- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; -- -- ptrs_idx++; -- -- } else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { -- -- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; -- -- #ifdef DEBUG_PUSCH_MAPPING -- printf("m %d\t l %d \t k %d \t txdataF: %d %d\n", -- m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1]); -- #endif -- -- m++; -- -- } else { -- -- ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = 0; -- ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = 0; -- -- } -+ for (int i=0; iofdm_symbol_size + k; -+ int32_t precodatatx_F = nr_layer_precoder(tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); -+ ((int16_t*)txdataF[ap])[(re_offset<<1)] = ((int16_t *) &precodatatx_F)[0]; -+ ((int16_t*)txdataF[ap])[(re_offset<<1) + 1] = ((int16_t *) &precodatatx_F)[1]; -+ -+ if (++k >= frame_parms->ofdm_symbol_size) -+ { -+ k -= frame_parms->ofdm_symbol_size; -+ } -+ } -+ } -+ } //RB loop -+ } // symbol loop -+ }// port loop - -- if (++k >= frame_parms->ofdm_symbol_size) -- k -= frame_parms->ofdm_symbol_size; -- } -- } -- } -- } -+ } //for (cwd_index = 0;cwd_index < num_of_codewords; cwd_index++) - - NR_UL_UE_HARQ_t *harq_process_ulsch=NULL; - harq_process_ulsch = UE->ulsch[thread_id][gNB_id][0]->harq_processes[harq_pid]; -diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h -index 11b5112a6c..600ba07cb3 100644 ---- a/openair1/PHY/defs_gNB.h -+++ b/openair1/PHY/defs_gNB.h -@@ -479,7 +479,7 @@ typedef struct { - /// \brief Cross-correlation of two UE signals. - /// - first index: rx antenna [0..nb_antennas_rx[ - /// - second index: symbol [0..] -- int32_t **rho; -+ int32_t ***rho; - /// \f$\log_2(\max|H_i|^2)\f$ - int16_t log2_maxh; - /// \brief Magnitude of Uplink Channel first layer (16QAM level/First 64QAM level). -@@ -509,6 +509,10 @@ typedef struct { - /// \brief llr values. - /// - first index: ? [0..1179743] (hard coded) - int16_t *llr; -+ /// \brief llr values per layer. -+ /// - first index: ? [0..3] (hard coded) -+ /// - first index: ? [0..1179743] (hard coded) -+ int16_t **llr_layers; - /// DMRS symbol index, to be updated every DMRS symbol within a slot. - uint8_t dmrs_symbol; - // PTRS symbol index, to be updated every PTRS symbol within a slot. -diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h -index 69978f5548..02988b590a 100644 ---- a/openair1/PHY/defs_nr_UE.h -+++ b/openair1/PHY/defs_nr_UE.h -@@ -229,6 +229,9 @@ typedef struct { - typedef struct { - /// TX buffers for multiple layers - int32_t *txdataF_layers[NR_MAX_NB_LAYERS]; -+ -+ /// TX buffers for UE-spec transmission -+ int32_t *txdataF_precoding[NR_MAX_NB_LAYERS]; - } NR_UE_PUSCH; - - typedef struct { -diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h -index c385d323e3..fbe094f41c 100644 ---- a/openair1/PHY/defs_nr_common.h -+++ b/openair1/PHY/defs_nr_common.h -@@ -93,7 +93,7 @@ - #define NR_MAX_CSET_DURATION 3 - - #define NR_MAX_NB_RBG 18 --#define NR_MAX_NB_LAYERS 2 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) -+#define NR_MAX_NB_LAYERS 4 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3) - #define NR_MAX_NB_CODEWORDS 2 - #define NR_MAX_NB_HARQ_PROCESSES 16 - #define NR_MAX_PDSCH_ENCODED_LENGTH (NR_MAX_NB_RB*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8*NR_MAX_NB_LAYERS) // 8 is the maximum modulation order (it was 950984 before !!) -@@ -104,11 +104,11 @@ - #define MAX_NUM_NR_DLSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) - #define MAX_NR_DLSCH_PAYLOAD_BYTES (MAX_NUM_NR_DLSCH_SEGMENTS*1056) - --#define MAX_NUM_NR_ULSCH_SEGMENTS 34 -+#define MAX_NUM_NR_ULSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) - #define MAX_NR_ULSCH_PAYLOAD_BYTES (MAX_NUM_NR_ULSCH_SEGMENTS*1056) - --#define MAX_NUM_NR_CHANNEL_BITS (14*273*12*8) // 14 symbols, 273 RB --#define MAX_NUM_NR_RE (14*273*12) -+#define MAX_NUM_NR_CHANNEL_BITS (4*14*273*12*8) // 14 symbols, 273 RB -+#define MAX_NUM_NR_RE (4*14*273*12) - #define NR_RX_NB_TH 1 - #define NR_NB_TH_SLOT 2 - -diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c -index d8fa11d157..640a0740ef 100644 ---- a/openair1/SCHED_NR/nr_ru_procedures.c -+++ b/openair1/SCHED_NR/nr_ru_procedures.c -@@ -526,7 +526,8 @@ void nr_fep0(RU_t *ru, int first_half) { - end_symbol = NR_SYMBOLS_PER_SLOT; - } - -- LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d\n", proc->tti_rx, first_half, start_symbol, end_symbol); -+ LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d, nb_antennas_rx = %d,N_TA_offset = %d\n", -+ proc->tti_rx, first_half, start_symbol, end_symbol,fp->nb_antennas_rx,ru->N_TA_offset); - // printf("fep0: slot %d\n",slot); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 1); -diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c -index 1685e206ae..63c708e565 100644 ---- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c -+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c -@@ -253,13 +253,13 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { - // if all segments are done - if (rdata->nbSegments == ulsch_harq->processedSegments) { - if (decodeSuccess) { -- LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", -+ LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", - gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); - ulsch_harq->status = SCH_IDLE; - ulsch_harq->round = 0; - ulsch->harq_mask &= ~(1 << rdata->harq_pid); - -- LOG_D(PHY, "ULSCH received ok \n"); -+ LOG_I(PHY, "ULSCH received ok \n"); - nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); - //dumpsig=1; - } else { -@@ -281,7 +281,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { - } - ulsch_harq->handled = 1; - -- LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); -+ LOG_I(PHY, "ULSCH %d in error\n",rdata->ulsch_id); - nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1,0); - } - /* -@@ -365,6 +365,14 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); -+ -+ -+ nr_ulsch_layer_demapping(gNB->pusch_vars[ULSCH_id]->llr, -+ pusch_pdu->nrOfLayers, -+ pusch_pdu->qam_mod_order, -+ G, -+ gNB->pusch_vars[ULSCH_id]->llr_layers); -+ - //---------------------------------------------------------- - //------------------- ULSCH unscrambling ------------------- - //---------------------------------------------------------- -@@ -731,7 +739,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { - (ulsch_harq->slot == slot_rx) && - (ulsch_harq->handled == 0)){ - -- LOG_D(PHY, "PUSCH detection started in frame %d slot %d\n", -+ LOG_I(PHY, "PUSCH detection started in frame %d slot %d\n", - frame_rx,slot_rx); - int num_dmrs=0; - for (int s=0;srx_pusch_stats); - no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); - if (no_sig) { -- LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); -+ LOG_I(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); - nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - return 1; - } -@@ -783,7 +791,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { - dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot) + gNB->pusch_thres) { - NR_gNB_SCH_STATS_t *stats=get_ulsch_stats(gNB,ulsch); - -- LOG_D(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, -+ LOG_I(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, - dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot), - dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres); - gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot; -diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c -index f6e4d90bee..8e1df435c3 100644 ---- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c -+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c -@@ -157,7 +157,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ - for (i = 0; i < ul_config->number_pdus; ++i){ - - AssertFatal(ul_config->ul_config_list[i].pdu_type <= FAPI_NR_UL_CONFIG_TYPES,"pdu_type %d out of bounds\n",ul_config->ul_config_list[i].pdu_type); -- LOG_D(PHY, "In %s: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); -+ LOG_I(PHY, "In %s i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); - - uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type, current_harq_pid, gNB_id = 0; - /* PRACH */ -@@ -180,6 +180,8 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ - if (harq_process_ul_ue){ - - nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &harq_process_ul_ue->pusch_pdu; -+ -+ LOG_I(PHY, "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n", __FUNCTION__, i, pusch_config_pdu->nrOfLayers,pusch_config_pdu->num_dmrs_cdm_grps_no_data); - - memcpy(pusch_pdu, pusch_config_pdu, sizeof(nfapi_nr_ue_pusch_pdu_t)); - -diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c -index 940931694c..0a0a9cc2f9 100644 ---- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c -+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c -@@ -270,9 +270,12 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, - AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN); -- -- memset(ue->common_vars.txdataF[0], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); -- -+ -+ for(int i=0; i< ue->frame_parms.nb_antennas_tx; ++i) -+ { -+ memset(ue->common_vars.txdataF[i], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); -+ } -+ - LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); - - -diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c -index 1eb6027936..d5a1054654 100644 ---- a/openair1/SIMULATION/NR_PHY/dlsim.c -+++ b/openair1/SIMULATION/NR_PHY/dlsim.c -@@ -768,7 +768,7 @@ int main(int argc, char **argv) - - prepare_scd(scd); - -- fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); -+ fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); - - /* RRC parameter validation for secondaryCellGroup */ - fix_scd(scd); -diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c -index 94aea36a67..fb8b4295ae 100644 ---- a/openair1/SIMULATION/NR_PHY/ulschsim.c -+++ b/openair1/SIMULATION/NR_PHY/ulschsim.c -@@ -137,6 +137,7 @@ int main(int argc, char **argv) - uint16_t nb_symb_sch = 12; - uint16_t nb_rb = 50; - uint8_t Imcs = 9; -+ uint8_t Nl = 1; - - double DS_TDL = .03; - -@@ -150,7 +151,7 @@ int main(int argc, char **argv) - randominit(0); - - //while ((c = getopt(argc, argv, "df:hpg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:")) != -1) { -- while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:")) != -1) { -+ while ((c = getopt(argc, argv, "hg:n:s:S:py:z:M:N:R:F:m:l:r:W:")) != -1) { - switch (c) { - /*case 'f': - write_output_file = 1; -@@ -251,7 +252,7 @@ int main(int argc, char **argv) - case 'y': - n_tx = atoi(optarg); - -- if ((n_tx == 0) || (n_tx > 2)) { -+ if ((n_tx == 0) || (n_tx > 4)) { - printf("Unsupported number of TX antennas %d. Exiting.\n", n_tx); - exit(-1); - } -@@ -261,7 +262,7 @@ int main(int argc, char **argv) - case 'z': - n_rx = atoi(optarg); - -- if ((n_rx == 0) || (n_rx > 2)) { -+ if ((n_rx == 0) || (n_rx > 4)) { - printf("Unsupported number of RX antennas %d. Exiting.\n", n_rx); - exit(-1); - } -@@ -299,6 +300,10 @@ int main(int argc, char **argv) - printf("Illegal PBCH phase (0-3) got %d\n", pbch_phase); - break;*/ - -+ case 'W': -+ Nl = atoi(optarg); -+ break; -+ - case 'm': - Imcs = atoi(optarg); - #ifdef DEBUG_NR_ULSCHSIM -@@ -335,13 +340,14 @@ int main(int argc, char **argv) - printf("-z Number of RX antennas used in UE\n"); - //printf("-i Relative strength of first intefering eNB (in dB) - cell_id mod 3 = 1\n"); - //printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n"); -+ printf("-W number of layer\n"); - printf("-M Multiple SSB positions in burst\n"); - printf("-N Nid_cell\n"); - printf("-R N_RB_UL\n"); - printf("-F Input filename (.txt format) for RX conformance testing\n"); -- printf("-m\n"); -- printf("-l\n"); -- printf("-r\n"); -+ printf("-m MCS\n"); -+ printf("-l number of symbol\n"); -+ printf("-r number of RB\n"); - //printf("-O oversampling factor (1,2,4,8,16)\n"); - //printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); - //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); -@@ -359,8 +365,8 @@ int main(int argc, char **argv) - snr1 = snr0 + 10; - - gNB2UE = new_channel_desc_scm(n_tx, -- n_rx, -- channel_model, -+ n_rx, -+ channel_model, - 61.44e6, //N_RB2sampling_rate(N_RB_DL), - 40e6, //N_RB2channel_bandwidth(N_RB_DL), - DS_TDL, -@@ -426,8 +432,7 @@ int main(int argc, char **argv) - uint8_t length_dmrs = 1; - uint8_t N_PRB_oh; - uint16_t N_RE_prime,code_rate; -- unsigned char mod_order; -- uint8_t Nl = 1; -+ unsigned char mod_order; - uint8_t rvidx = 0; - uint8_t UE_id = 0; - -@@ -437,9 +442,14 @@ int main(int argc, char **argv) - - NR_UE_ULSCH_t *ulsch_ue = UE->ulsch[0][0][0]; - -+ if ((Nl==4)||(Nl==3)) -+ { -+ nb_re_dmrs = nb_re_dmrs*2; -+ } -+ - mod_order = nr_get_Qm_ul(Imcs, 0); - code_rate = nr_get_code_rate_ul(Imcs, 0); -- available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1); -+ available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, Nl); - TBS = nr_compute_tbs(mod_order,code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, 0, Nl); - - printf("\nAvailable bits %u TBS %u mod_order %d\n", available_bits, TBS, mod_order); -diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c -index 69316d6b88..b6cfae3fe1 100644 ---- a/openair1/SIMULATION/NR_PHY/ulsim.c -+++ b/openair1/SIMULATION/NR_PHY/ulsim.c -@@ -282,7 +282,7 @@ int main(int argc, char **argv) - int gNB_id = 0; - int ap; - int tx_offset; -- int32_t txlev=0; -+ int32_t txlev_sum = 0, atxlev[4]; - int start_rb = 0; - int UE_id =0; // [hna] only works for UE_id = 0 because NUMBER_OF_NR_UE_MAX is set to 1 (phy_init_nr_gNB causes segmentation fault) - float target_error_rate = 0.01; -@@ -307,7 +307,7 @@ int main(int argc, char **argv) - uint16_t ptrsSymbPerSlot = 0; - uint16_t ptrsRePerSymb = 0; - -- uint8_t transform_precoding = 1; // 0 - ENABLE, 1 - DISABLE -+ uint8_t transformPrecoder = transformPrecoder_disabled; // 0 - ENABLE, 1 - DISABLE - uint8_t num_dmrs_cdm_grps_no_data = 1; - uint8_t mcs_table = 0; - -@@ -329,7 +329,7 @@ int main(int argc, char **argv) - /* initialize the sin-cos table */ - InitSinLUT(); - -- while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:ikl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z")) != -1) { -+ while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:kl:m:n:p:r:s:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z:W:")) != -1) { - printf("handling optarg %c\n",c); - switch (c) { - -@@ -363,8 +363,8 @@ int main(int argc, char **argv) - scg_fd = fopen(optarg, "r"); - - if (scg_fd == NULL) { -- printf("Error opening %s\n", optarg); -- exit(-1); -+ printf("Error opening %s\n", optarg); -+ exit(-1); - } - - break; -@@ -437,6 +437,10 @@ int main(int argc, char **argv) - case 'm': - Imcs = atoi(optarg); - break; -+ -+ case 'W': -+ precod_nbr_layers = atoi(optarg); -+ break; - - case 'n': - n_trials = atoi(optarg); -@@ -485,9 +489,9 @@ int main(int argc, char **argv) - case 'y': - n_tx = atoi(optarg); - -- if ((n_tx == 0) || (n_tx > 2)) { -- printf("Unsupported number of tx antennas %d\n", n_tx); -- exit(-1); -+ if ((n_tx == 0) || (n_tx > 4)) { -+ printf("Unsupported number of tx antennas %d\n", n_tx); -+ exit(-1); - } - - break; -@@ -496,8 +500,8 @@ int main(int argc, char **argv) - n_rx = atoi(optarg); - - if ((n_rx == 0) || (n_rx > 8)) { -- printf("Unsupported number of rx antennas %d\n", n_rx); -- exit(-1); -+ printf("Unsupported number of rx antennas %d\n", n_rx); -+ exit(-1); - } - - break; -@@ -506,8 +510,8 @@ int main(int argc, char **argv) - input_fd = fopen(optarg, "r"); - - if (input_fd == NULL) { -- printf("Problem with filename %s\n", optarg); -- exit(-1); -+ printf("Problem with filename %s\n", optarg); -+ exit(-1); - } - - break; -@@ -568,11 +572,11 @@ int main(int argc, char **argv) - - case 'Z': - -- transform_precoding = 0; // enabled -+ transformPrecoder = transformPrecoder_enabled; - num_dmrs_cdm_grps_no_data = 2; - mcs_table = 3; - -- printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transform_precoding); -+ printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transformPrecoder); - - break; - -@@ -611,6 +615,7 @@ int main(int argc, char **argv) - printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n"); - printf("-Q If -F used, read parameters from file\n"); - printf("-Z If -Z is used, SC-FDMA or transform precoding is enabled in Uplink \n"); -+ printf("-W Num of layer for PUSCH\n"); - exit(-1); - break; - -@@ -713,7 +718,7 @@ int main(int argc, char **argv) - - prepare_scd(scd); - -- fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0); -+ fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, n_rx, 0, 0, 0); - - // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); - -@@ -724,9 +729,9 @@ int main(int argc, char **argv) - - gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; - // common configuration -- rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,0, 0, NULL); -+ rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,0, 0, NULL); - // UE dedicated configuration -- rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); -+ rrc_mac_config_req_gNB(0,0, n_tx, n_rx, n_tx, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); - frame_parms->nb_antennas_tx = n_tx; - frame_parms->nb_antennas_rx = n_rx; - nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; -@@ -870,14 +875,18 @@ int main(int argc, char **argv) - uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); - printf("num dmrs sym %d\n",number_dmrs_symbols); - uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; -- -- // if transform precoding is enabled -- if (transform_precoding == 0) { -+ -+ if ((frame_parms->nb_antennas_tx==4)&&(precod_nbr_layers==4)) -+ { -+ num_dmrs_cdm_grps_no_data = 2; -+ } -+ -+ if (transformPrecoder == transformPrecoder_enabled) { - - AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); - - int8_t index = get_index_for_dmrs_lowpapr_seq((NR_NB_SC_PER_RB/2) * nb_rb); -- AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); -+ AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); - - dmrs_config_type = pusch_dmrs_type1; - -@@ -886,7 +895,7 @@ int main(int argc, char **argv) - - nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; - -- unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1); -+ unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, precod_nbr_layers); - unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); - - -@@ -1082,14 +1091,14 @@ int main(int argc, char **argv) - pusch_pdu->mcs_table = mcs_table; - pusch_pdu->target_code_rate = code_rate; - pusch_pdu->qam_mod_order = mod_order; -- pusch_pdu->transform_precoding = transform_precoding; -+ pusch_pdu->transformPrecoder = transformPrecoder; - pusch_pdu->data_scrambling_id = *scc->physCellId; -- pusch_pdu->nrOfLayers = 1; -+ pusch_pdu->nrOfLayers = precod_nbr_layers; - pusch_pdu->ul_dmrs_symb_pos = l_prime_mask; - pusch_pdu->dmrs_config_type = dmrs_config_type; - pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; - pusch_pdu->scid = 0; -- pusch_pdu->dmrs_ports = 1; -+ pusch_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; - pusch_pdu->resource_alloc = 1; - pusch_pdu->rb_start = start_rb; -@@ -1109,7 +1118,7 @@ int main(int argc, char **argv) - pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; - - // if transform precoding is enabled -- if (transform_precoding == 0) { -+ if (transformPrecoder == transformPrecoder_enabled) { - - pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; // U as defined in 38.211 section 6.4.1.1.1.2 - pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; // V as defined in 38.211 section 6.4.1.1.1.2 -@@ -1167,10 +1176,10 @@ int main(int argc, char **argv) - ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t)); - ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; - -- ul_config.ul_config_list[0].pusch_config_pdu.transform_precoding = transform_precoding; -+ ul_config.ul_config_list[0].pusch_config_pdu.transformPrecoder = transformPrecoder; - - // if transform precoding is enabled -- if (transform_precoding == 0) { -+ if (transformPrecoder == transformPrecoder_enabled) { - - ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_group_number = *scc->physCellId % 30;// U as defined in 38.211 section 6.4.1.1.1.2 - ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;// V as defined in 38.211 section 6.4.1.1.1.2 -@@ -1198,28 +1207,54 @@ int main(int argc, char **argv) - LOG_D(PHY, "Sending Uplink data \n"); - nr_ue_pusch_common_procedures(UE, - slot, -- &UE->frame_parms,1); -- -- if (n_trials==1) { -- LOG_M("txsig0.m","txs0", UE->common_vars.txdata[0],frame_parms->samples_per_subframe*10,1,1); -+ &UE->frame_parms, -+ frame_parms->nb_antennas_tx); -+ -+ -+ if (n_trials==1) -+ { -+ LOG_M("txsig0.m","txs0", &UE->common_vars.txdata[0][slot_offset],slot_length,1,1); - LOG_M("txsig0F.m","txs0F", UE->common_vars.txdataF[0],frame_parms->ofdm_symbol_size*14,1,1); -+ if (precod_nbr_layers > 1) -+ { -+ LOG_M("txsig1.m","txs1", &UE->common_vars.txdata[1][slot_offset],slot_length,1,1); -+ LOG_M("txsig1F.m","txs1F", UE->common_vars.txdataF[1],frame_parms->ofdm_symbol_size*14,1,1); -+ if (precod_nbr_layers==4) -+ { -+ LOG_M("txsig2.m","txs2", &UE->common_vars.txdata[2][slot_offset],slot_length,1,1); -+ LOG_M("txsig3.m","txs3", &UE->common_vars.txdata[3][slot_offset],slot_length,1,1); -+ -+ LOG_M("txsig2F.m","txs2F", UE->common_vars.txdataF[2],frame_parms->ofdm_symbol_size*14,1,1); -+ LOG_M("txsig3F.m","txs3F", UE->common_vars.txdataF[3],frame_parms->ofdm_symbol_size*14,1,1); -+ } -+ } - } - /////////// - //////////////////////////////////////////////////// - tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); -- -- txlev = signal_energy(&UE->common_vars.txdata[0][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], -+ txlev_sum = 0; -+ for (int aa=0; aanb_antennas_tx; aa++) -+ { -+ atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], - frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); -- } -- else n_trials = 1; -- -- if (input_fd == NULL ) { -+ -+ txlev_sum += atxlev[aa]; -+ -+ if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,atxlev[aa],10*log10((double)atxlev[aa]),txlev_sum); -+ } -+ } -+ else -+ { -+ n_trials = 1; -+ } - -- sigma_dB = 10 * log10((double)txlev * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; -+ if (input_fd == NULL ) -+ { -+ sigma_dB = 10 * log10((double)txlev_sum * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; - sigma = pow(10,sigma_dB/10); - - -- if(n_trials==1) printf("sigma %f (%f dB), txlev %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev),(double)(double) -+ if(n_trials==1) printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev_sum),(double)(double) - frame_parms->ofdm_symbol_size/(12*nb_rb)); - - for (i=0; imax_Doppler == 0) { -+ if (UE2gNB->max_Doppler == 0) -+ { - multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); - } else { - multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); - } -- for (i=0; inb_antennas_rx; ap++) { -+ for (i=0; inb_antennas_rx; ap++) -+ { -+ if (channel_model == AWGN) -+ { -+ double H_awgn[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 -+ {0.0, 1.0, 0.0, 0.0}, //rx 1 -+ {0.0, 0.0, 1.0, 0.0}, //rx 2 -+ {0.0, 0.0, 0.0, 1.0}};//rx 3 -+ #if 0 -+ double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 -+ {0.5, 1.0, 0.5, 0.25}, //rx 1 -+ {0.25, 0.5, 1.0, 0.5}, //rx 2 -+ {0.125, 0.25, 0.5, 1.0}};//rx 3 -+ #endif -+ // sum up signals from different Tx antennas -+ r_re[ap][i] = 0; -+ r_im[ap][i] = 0; -+ -+ for (int aa=0; aaofdm_symbol_size/(12*nb_rb))) - SNR;; -+ sigma = pow(10,sigma_dB/10); -+ - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); -+ -+ #if 0 -+ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i])); // convert to fixed point -+ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i])); -+ -+ -+ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) ] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i) ]; // convert to fixed point -+ ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i)+1 ]; -+ #endif -+ - /* Add phase noise if enabled */ - if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)], -@@ -1250,7 +1324,8 @@ int main(int argc, char **argv) - } /*End input_fd */ - - -- if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { -+ if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) -+ { - set_ptrs_symb_idx(&ptrsSymPos, - pusch_pdu->nr_of_symbols, - pusch_pdu->start_symbol_index, -@@ -1268,24 +1343,37 @@ int main(int argc, char **argv) - gNB->UL_INFO.rx_ind.number_of_pdus = 0; - gNB->UL_INFO.crc_ind.number_crcs = 0; - -- phy_procedures_gNB_common_RX(gNB, frame, slot); -+ phy_procedures_gNB_common_RX(gNB, frame, slot); - -- ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); -+ ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); - -- if (n_trials==1 && round==0) { -+ if (n_trials==1 && round==0) -+ { - LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1); - -- LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0]+start_symbol*frame_parms->ofdm_symbol_size,nb_symb_sch*frame_parms->ofdm_symbol_size,1,1); -- -+ LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],14*frame_parms->ofdm_symbol_size,1,1); -+ if (precod_nbr_layers > 1) -+ { -+ LOG_M("rxsig1.m","rx1",&gNB->common_vars.rxdata[1][slot_offset],slot_length,1,1); -+ LOG_M("rxsigF1.m","rxsF1",gNB->common_vars.rxdataF[1],14*frame_parms->ofdm_symbol_size,1,1); -+ if (precod_nbr_layers==4) -+ { -+ LOG_M("rxsig2.m","rx2",&gNB->common_vars.rxdata[2][slot_offset],slot_length,1,1); -+ LOG_M("rxsig3.m","rx3",&gNB->common_vars.rxdata[3][slot_offset],slot_length,1,1); -+ -+ LOG_M("rxsigF2.m","rxsF2",gNB->common_vars.rxdataF[2],14*frame_parms->ofdm_symbol_size,1,1); -+ LOG_M("rxsigF3.m","rxsF3",gNB->common_vars.rxdataF[3],14*frame_parms->ofdm_symbol_size,1,1); -+ } -+ } - } - - - if (n_trials == 1 && round==0) { --#ifdef __AVX2__ -+ #ifdef __AVX2__ - int off = ((nb_rb&1) == 1)? 4:0; --#else -+ #else - int off = 0; --#endif -+ #endif - - LOG_M("rxsigF0_ext.m","rxsF0_ext", - &gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -@@ -1298,11 +1386,77 @@ int main(int argc, char **argv) - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_M("rxsigF0_comp.m","rxsF0_comp", - &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -- LOG_M("chmagF0.m","chmF0", -- &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -- LOG_M("chmagbF0.m","chmbF0", -- &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -- if (n_rx == 2) { -+ LOG_M("chmagF0.m","chmF0", -+ &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("chmagbF0.m","chmbF0", -+ &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF0_llrlayers0.m","rxsF0_llrlayers0", -+ &gNB->pusch_vars[0]->llr_layers[0][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ -+ if (precod_nbr_layers==2) -+ { -+ LOG_M("rxsigF1_ext.m","rxsF1_ext", -+ &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ -+ LOG_M("chestF3.m","chF3", -+ &gNB->pusch_vars[0]->ul_ch_estimates[3][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); -+ -+ LOG_M("chestF3_ext.m","chF3_ext", -+ &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], -+ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ -+ LOG_M("rxsigF2_comp.m","rxsF2_comp", -+ &gNB->pusch_vars[0]->rxdataF_comp[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ -+ LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", -+ &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ -+ } -+ -+ if (precod_nbr_layers==4) -+ { -+ LOG_M("rxsigF1_ext.m","rxsF1_ext", -+ &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF2_ext.m","rxsF2_ext", -+ &gNB->pusch_vars[0]->rxdataF_ext[2][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF3_ext.m","rxsF3_ext", -+ &gNB->pusch_vars[0]->rxdataF_ext[3][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ -+ LOG_M("chestF5.m","chF5", -+ &gNB->pusch_vars[0]->ul_ch_estimates[5][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); -+ LOG_M("chestF10.m","chF10", -+ &gNB->pusch_vars[0]->ul_ch_estimates[10][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); -+ LOG_M("chestF15.m","chF15", -+ &gNB->pusch_vars[0]->ul_ch_estimates[15][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); -+ -+ -+ LOG_M("chestF5_ext.m","chF5_ext", -+ &gNB->pusch_vars[0]->ul_ch_estimates_ext[5][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], -+ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("chestF10_ext.m","chF10_ext", -+ &gNB->pusch_vars[0]->ul_ch_estimates_ext[10][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], -+ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("chestF15_ext.m","chF15_ext", -+ &gNB->pusch_vars[0]->ul_ch_estimates_ext[15][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], -+ (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ -+ -+ LOG_M("rxsigF4_comp.m","rxsF4_comp", -+ &gNB->pusch_vars[0]->rxdataF_comp[4][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF8_comp.m","rxsF8_comp", -+ &gNB->pusch_vars[0]->rxdataF_comp[8][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF12_comp.m","rxsF12_comp", -+ &gNB->pusch_vars[0]->rxdataF_comp[12][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); -+ LOG_M("rxsigF0_llrlayers1.m","rxsF0_llrlayers1", -+ &gNB->pusch_vars[0]->llr_layers[1][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ LOG_M("rxsigF0_llrlayers2.m","rxsF0_llrlayers2", -+ &gNB->pusch_vars[0]->llr_layers[2][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ LOG_M("rxsigF0_llrlayers3.m","rxsF0_llrlayers3", -+ &gNB->pusch_vars[0]->llr_layers[3][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ } -+ -+ #if 0 -+ if (n_rx == 2) { - LOG_MM("rxsigF0_comp.m","rxsF1_comp", - &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_ext.m","rxsF1_ext", -@@ -1349,9 +1503,10 @@ int main(int argc, char **argv) - LOG_MM("chmagbF0.m","chmbF3", - &gNB->pusch_vars[0]->ul_ch_magb[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - } -+ #endif - - LOG_M("rxsigF0_llr.m","rxsF0_llr", -- &gNB->pusch_vars[0]->llr[0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); -+ &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); - } - //////////////////////////////////////////////////////////// - -diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c -index 3f4be9dd58..7e5be9eeba 100644 ---- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c -+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c -@@ -2708,6 +2708,9 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, - LOG_D(NR_MAC,"dci_pdu->srs_resource_indicator.nbits %d\n",dci_pdu->srs_resource_indicator.nbits); - // Precoding info and number of layers - long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); -+ -+ pusch_antenna_ports = *pusch_Config->maxRank; -+ - dci_pdu->precoding_information.nbits=0; - if (pusch_Config && - pusch_Config->txConfig != NULL){ -diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c -index c23d4bb073..963723725f 100644 ---- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c -+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c -@@ -190,7 +190,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - else - transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; - } -- -+ pusch_config_pdu->transformPrecoder = transformPrecoder; - - /* PRECOD_NBR_LAYERS */ - if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)); -@@ -198,11 +198,12 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - - if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)){ - -- uint8_t n_antenna_port = 0; //FIXME!!! -+ uint8_t n_antenna_port = mac->phy_config.config_req.carrier_config.num_tx_ant; - - if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits - -- if (n_antenna_port == 4){ // 4 antenna port and the higher layer parameter txConfig = codebook -+ if (n_antenna_port == 4) -+ { // 4 antenna port and the higher layer parameter txConfig = codebook - - // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4 - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) -@@ -212,54 +213,56 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5]; - } - } - - // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1 - if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) - || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) -- && (*pusch_Config->maxRank == 1)){ -+ && (*pusch_Config->maxRank == 1)) -+ { - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11]; - } - } - } - -- if (n_antenna_port == 4){ // 2 antenna port and the higher layer parameter txConfig = codebook -+ if (n_antenna_port == 2) -+ { // 2 antenna port and the higher layer parameter txConfig = codebook - // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2 -- if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)){ -- -+ if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) -+ { - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15]; - } - - } -@@ -267,16 +270,17 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1 - if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) - || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) -- && (*pusch_Config->maxRank == 1)){ -+ && (*pusch_Config->maxRank == 1)) -+ { - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17]; - } - - if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){ - pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18]; -- pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; -+ pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19]; - } - - } -@@ -285,9 +289,9 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - - /*-------------------- Changed to enable Transform precoding in RF SIM------------------------------------------------*/ - -- /*if (pusch_config_pdu->transform_precoding == transform_precoder_enabled) { -+ /*if (pusch_config_pdu->transformPrecoder == transformPrecoder_enabled) { - -- pusch_config_dedicated->transform_precoder = transform_precoder_enabled; -+ pusch_config_dedicated->transform_precoder = transformPrecoder_enabled; - - if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) { - -@@ -309,7 +313,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con - - } - } else -- pusch_config_dedicated->transform_precoder = transform_precoder_disabled;*/ -+ pusch_config_dedicated->transformPrecoder = ttransformPrecoder_disabled;*/ - } - - // todo: this function shall be reviewed completely because of the many comments left by the author -@@ -342,7 +346,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf - } - long *max_length = NULL; - long *dmrs_type = NULL; -- LOG_D(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); -+ LOG_I(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); - - if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) { - max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength; -@@ -353,7 +357,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf - dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type; - } - -- LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); -+ LOG_I(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && - (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC -@@ -369,35 +373,32 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf - } - - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && -- (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11 -+ (dmrs_type == NULL) && (max_length == NULL)) -+ { // tables 7.3.1.1.2-8/9/10/11 -+ -+ if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)) -+ { -+ rank = pusch_config_pdu->nrOfLayers; -+ } - - if (rank == 1) { -- pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC -- pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val); //TBC -+ pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; -+ pusch_config_pdu->dmrs_ports =1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val)); - } - - if (rank == 2){ -- pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC -- pusch_config_pdu->dmrs_ports = 0; //FIXME -- //pusch_config_pdu->dmrs_ports[0] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?0:2):0; -- //pusch_config_pdu->dmrs_ports[1] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?2:3):1; -+ pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; -+ pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val> 2)?0x5:0xc):0x3; - } - - if (rank == 3){ -- pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC -- pusch_config_pdu->dmrs_ports = 0; //FIXME -- //pusch_config_pdu->dmrs_ports[0] = 0; -- //pusch_config_pdu->dmrs_ports[1] = 1; -- //pusch_config_pdu->dmrs_ports[2] = 2; -+ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; -+ pusch_config_pdu->dmrs_ports = ((1<num_dmrs_cdm_grps_no_data = 2; //TBC -- pusch_config_pdu->dmrs_ports = 0; //FIXME -- //pusch_config_pdu->dmrs_ports[0] = 0; -- //pusch_config_pdu->dmrs_ports[1] = 1; -- //pusch_config_pdu->dmrs_ports[2] = 2; -- //pusch_config_pdu->dmrs_ports[3] = 3; -+ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; -+ pusch_config_pdu->dmrs_ports = ((1<n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME - } - } -- LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); -+ LOG_I(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); - } - - // Configuration of Msg3 PDU according to clauses: -@@ -542,6 +543,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1; - pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; - pusch_config_pdu->nrOfLayers = 1; -+ pusch_config_pdu->Tpmi = 0; - pusch_config_pdu->rnti = rnti; - NR_BWP_UplinkCommon_t *initialUplinkBWP; - if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; -@@ -634,7 +636,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - pusch_config_pdu->scid = 0; - - // Transform precoding according to 6.1.3 UE procedure for applying transform precoding on PUSCH in 38.214 -- pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out -+ pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out - - // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214 - pusch_config_pdu->resource_alloc = (mac->cg) ? pusch_Config->resourceAllocation : 1; -@@ -680,7 +682,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - - /* Transform precoding */ - if (rnti_type != NR_RNTI_CS || (rnti_type == NR_RNTI_CS && dci->ndi == 1)) { -- pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); -+ pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); - } - - /*DCI format-related configuration*/ -@@ -716,7 +718,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - - /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/ - -- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { -+ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) { - - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; - -@@ -761,7 +763,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - pusch_config_pdu->mcs_index = dci->mcs; - - /* MCS TABLE */ -- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { -+ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { - pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_Table : NULL, 0, *dci_format, rnti_type, target_ss, false); - } else { - pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, 1, *dci_format, rnti_type, target_ss, false); -@@ -798,9 +800,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - mappingtype, add_pos, dmrslength, - pusch_config_pdu->start_symbol_index, - mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); -- if ((mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) -- pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; -- else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) -+ if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) -+ { -+ if (*dci_format != NR_UL_DCI_FORMAT_0_1) -+ { -+ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; -+ } -+ } -+ else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)) - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; - - // Num PRB Overhead from PUSCH-ServingCellConfig -@@ -821,7 +828,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, - mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup && - mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB && - mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { -- if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { -+ if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { - nfapi_nr_ue_ptrs_ports_t ptrs_ports_list; - pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list; - valid_ptrs_setup = set_ul_ptrs_values(mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup, -@@ -909,6 +916,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in - - fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id); - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) -+ LOG_I(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); - mac->if_module->scheduled_response(&scheduled_response); - } - else { -@@ -1022,6 +1030,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in - - fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, rx_frame, rx_slot, ul_info->thread_id); - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){ -+ LOG_I(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); - mac->if_module->scheduled_response(&scheduled_response); - } - pthread_mutex_lock(&ul_config->mutex_ul_config); -diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c -index 1cb3fdb708..d9c98852a3 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/config.c -+++ b/openair2/LAYER2/NR_MAC_gNB/config.c -@@ -388,7 +388,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts - cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts; - AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n"); - cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG; -- LOG_I(NR_MAC,"Set TX/RX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); -+ LOG_I(NR_MAC,"Set RX antenna number to %d, Set TX antenna number to %d (num ssb %d: %x,%x)\n",cfg->carrier_config.num_tx_ant.value,cfg->carrier_config.num_rx_ant.value,num_ssb,cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,cfg->ssb_table.ssb_mask_list[1].ssb_mask.value); - AssertFatal(cfg->carrier_config.num_tx_ant.value > 0,"carrier_config.num_tx_ant.value %d !\n",cfg->carrier_config.num_tx_ant.value ); - cfg->num_tlv++; - cfg->num_tlv++; -diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c -index 6ac7f3f82e..5de36bb2db 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c -+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c -@@ -977,9 +977,9 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, - pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); - pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); - if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) -- pusch_pdu->transform_precoding = 1; -+ pusch_pdu->transformPrecoder = 1; - else -- pusch_pdu->transform_precoding = 0; -+ pusch_pdu->transformPrecoder = 0; - pusch_pdu->data_scrambling_id = *scc->physCellId; - pusch_pdu->nrOfLayers = 1; - pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); -diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c -index abc007197d..9cbbe7d9a1 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c -+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c -@@ -1139,13 +1139,14 @@ void nr_schedule_ue_spec(module_id_t module_id, - dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; - LOG_D(NR_MAC, - "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " -- "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", -+ "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", - frame, - slot, - dci_payload.frequency_domain_assignment.val, - pdsch_pdu->rbStart, - pdsch_pdu->rbSize, - pdsch_pdu->BWPSize, -+ pdsch_pdu->nrOfLayers, - dci_payload.time_domain_assignment.val, - dci_payload.vrb_to_prb_mapping.val, - dci_payload.mcs, -diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c -index f1005cea70..8f7c856a30 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c -+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c -@@ -405,6 +405,7 @@ void nr_preprocessor_phytest(module_id_t module_id, - - uint32_t target_ul_mcs = 9; - uint32_t target_ul_bw = 50; -+uint32_t target_ul_Nl = 1; - uint64_t ulsch_slot_bitmap = (1 << 8); - bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot) - { -@@ -446,15 +447,21 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ - - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; -- const uint8_t num_dmrs_cdm_grps_no_data = 1; -+ uint8_t num_dmrs_cdm_grps_no_data = 1; -+ if ((target_ul_Nl==4)||(target_ul_Nl==3)) -+ { -+ num_dmrs_cdm_grps_no_data = 2; -+ } -+ - /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or - * num_dmrs_cdm_grps_no_data has changed and only then recompute */ - NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format -+ || ps->nrOfLayers != target_ul_Nl - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) -- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data, ps); -+ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); - - uint16_t rbStart = 0; - uint16_t rbSize; -@@ -525,6 +532,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ - sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; - - /* Calculate TBS from MCS */ -+ ps->nrOfLayers = target_ul_Nl; - sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); - if (ps->pusch_Config->tp_pi2BPSK -@@ -539,7 +547,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ - ps->N_PRB_DMRS * ps->num_dmrs_symb, - 0, // nb_rb_oh - 0, -- 1 /* NrOfLayers */) -+ ps->nrOfLayers /* NrOfLayers */) - >> 3; - - /* mark the corresponding RBs as used */ -diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c -index 1c0cb0353e..4583da876f 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c -+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c -@@ -355,6 +355,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, - long dci_format, - int tda, - uint8_t num_dmrs_cdm_grps_no_data, -+ uint8_t nrOfLayers, - NR_pusch_semi_static_t *ps) - { - ps->dci_format = dci_format; -@@ -371,11 +372,11 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, - - ps->pusch_Config = ubwp?ubwp->bwp_Dedicated->pusch_Config->choice.setup:(ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); - if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) -- ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; -+ ps->transformPrecoder = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; - else -- ps->transform_precoding = *ps->pusch_Config->transformPrecoder; -+ ps->transformPrecoder = *ps->pusch_Config->transformPrecoder; - const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; -- if (ps->transform_precoding) -+ if (ps->transformPrecoder) - ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_Table : NULL, - 0, - ps->dci_format, -@@ -392,6 +393,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, - num_dmrs_cdm_grps_no_data = 2; // in case of transform precoding - no Data sent in DMRS symbol - } - -+ ps->nrOfLayers = nrOfLayers; - ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; - - /* DMRS calculations */ -@@ -689,8 +691,21 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, - "Non Codebook configuration non supported\n"); - dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS - } -+ AssertFatal((pusch_pdu->Tpmi==0), "unsupport Tpmi\n"); -+ dci_pdu_rel15->precoding_information.val= 0; -+ if (pusch_pdu->nrOfLayers == 2) -+ { -+ dci_pdu_rel15->precoding_information.val = 4; -+ } -+ else if (pusch_pdu->nrOfLayers == 4) -+ { -+ dci_pdu_rel15->precoding_information.val = 11; -+ } -+ -+ // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 - // Antenna Ports -- dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank -+ dci_pdu_rel15->antenna_ports.val = 0; -+ - // DMRS sequence initialization - dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid; - break; -@@ -699,11 +714,14 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, - } - - LOG_D(NR_MAC, -- "%s() ULDCI type 0 payload: freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n", -+ "%s() ULDCI type 0 payload: dci_format %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, precoding_information.val %d antenna_ports.val %d mcs %d tpc %d ndi %d rv %d\n", - __func__, -+ dci_format, - dci_pdu_rel15->frequency_domain_assignment.val, - dci_pdu_rel15->time_domain_assignment.val, - dci_pdu_rel15->frequency_hopping_flag.val, -+ dci_pdu_rel15->precoding_information.val, -+ dci_pdu_rel15->antenna_ports.val, - dci_pdu_rel15->mcs, - dci_pdu_rel15->tpc, - dci_pdu_rel15->ndi, -diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c -index 9a6fa32b5f..269d6c5359 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c -+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c -@@ -905,7 +905,7 @@ bool allocate_ul_retransmission(module_id_t module_id, - NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); -- -+ const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; - const int tda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; - LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); -@@ -926,8 +926,9 @@ bool allocate_ul_retransmission(module_id_t module_id, - - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format -+ || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) -- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); -+ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); - LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); - } else { - /* the retransmission will use a different time domain allocation, check -@@ -939,7 +940,7 @@ bool allocate_ul_retransmission(module_id_t module_id, - rbSize++; - NR_pusch_semi_static_t temp_ps; - int dci_format = get_dci_format(sched_ctrl); -- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, &temp_ps); -+ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, &temp_ps); - uint32_t new_tbs; - uint16_t new_rbSize; - bool success = nr_find_nb_rb(retInfo->Qm, -@@ -1094,7 +1095,7 @@ void pf_ul(module_id_t module_id, - if (max_num_ue < 0) - return; - -- LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d\n", min_rb, rbStart); -+ LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", min_rb, rbStart, ps->num_dmrs_cdm_grps_no_data); - while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; - if (rbStart + min_rb >= bwpSize) { - LOG_W(NR_MAC, "cannot allocate continuous UL data for UE %d/RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d\n", -@@ -1106,13 +1107,15 @@ void pf_ul(module_id_t module_id, - /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or - * num_dmrs_cdm_grps_no_data has changed and only then recompute */ -+ const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; - int dci_format = get_dci_format(sched_ctrl); - const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format -+ || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) -- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); -+ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data,nrOfLayers, ps); - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - sched_pusch->mcs = 9; - update_ul_ue_R_Qm(sched_pusch, ps); -@@ -1125,7 +1128,7 @@ void pf_ul(module_id_t module_id, - ps->N_PRB_DMRS * ps->num_dmrs_symb, - 0, // nb_rb_oh - 0, -- 1 /* NrOfLayers */) -+ ps->nrOfLayers) - >> 3; - - /* Mark the corresponding RBs as used */ -@@ -1205,13 +1208,15 @@ void pf_ul(module_id_t module_id, - /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or - * num_dmrs_cdm_grps_no_data has changed and only then recompute */ -+ const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; - int dci_format = get_dci_format(sched_ctrl); - const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format -+ || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) -- nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); -+ nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers,ps); - update_ul_ue_R_Qm(sched_pusch, ps); - - /* Calculate the current scheduling bytes and the necessary RBs */ -@@ -1473,7 +1478,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) - sched_ctrl->last_ul_slot = sched_pusch->slot; - - LOG_D(NR_MAC, -- "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", -+ "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", - frame, - slot, - rnti, -@@ -1486,6 +1491,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) - ps->nrOfSymbols, - ps->ul_dmrs_symb_pos, - sched_pusch->mcs, -+ ps->nrOfLayers, -+ ps->num_dmrs_cdm_grps_no_data, - sched_pusch->tb_size, - harq_id, - cur_harq->round, -@@ -1532,17 +1539,18 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) - pusch_pdu->qam_mod_order = sched_pusch->Qm; - pusch_pdu->mcs_index = sched_pusch->mcs; - pusch_pdu->mcs_table = ps->mcs_table; -- pusch_pdu->transform_precoding = ps->transform_precoding; -+ pusch_pdu->transformPrecoder = ps->transformPrecoder; - if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) - pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; - else - pusch_pdu->data_scrambling_id = *scc->physCellId; -- pusch_pdu->nrOfLayers = 1; -+ pusch_pdu->nrOfLayers = ps->nrOfLayers; -+ pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; - - /* FAPI: DMRS */ - pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos; - pusch_pdu->dmrs_config_type = ps->dmrs_config_type; -- if (pusch_pdu->transform_precoding) { // transform precoding disabled -+ if (pusch_pdu->transformPrecoder) { // transform precoding disabled - long *scramblingid=NULL; - if (ps->NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) - scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; -@@ -1562,7 +1570,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) - } - pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] - pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data; -- pusch_pdu->dmrs_ports = 1; -+ pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); - - /* FAPI: Pusch Allocation in frequency domain */ - pusch_pdu->resource_alloc = 1; //type 1 -@@ -1588,7 +1596,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) - LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); - /* TRANSFORM PRECODING --------------------------------------------------------*/ - -- if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ -+ if (pusch_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled){ - - // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled - pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30; -diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h -index 91221276b0..8a560580c9 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h -+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h -@@ -298,6 +298,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, - long dci_format, - int tda, - uint8_t num_dmrs_cdm_grps_no_data, -+ uint8_t nrOfLayers, - NR_pusch_semi_static_t *ps); - - uint8_t nr_get_tpc(int target, uint8_t cqi, int incr); -diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h -index 27f42f4b1d..66b10dad42 100644 ---- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h -+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h -@@ -318,13 +318,14 @@ typedef struct NR_sched_pucch { - typedef struct NR_pusch_semi_static_t { - int dci_format; - int time_domain_allocation; -+ uint8_t nrOfLayers; - uint8_t num_dmrs_cdm_grps_no_data; - - int startSymbolIndex; - int nrOfSymbols; - - NR_PUSCH_Config_t *pusch_Config; -- uint8_t transform_precoding; -+ uint8_t transformPrecoder; - uint8_t mcs_table; - - long mapping_type; -diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c -index ff6923429e..52d03b5e56 100755 ---- a/openair2/RRC/NR/MESSAGES/asn1_msg.c -+++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c -@@ -1867,6 +1867,7 @@ int16_t do_RRCReconfiguration( - // 1, - // 1, - // carrier->pdsch_AntennaPorts, -+ // carrier->pusch_AntennaPorts, - // carrier->initial_csi_index[ue_context_p->local_uid + 1], - // ue_context_pP->local_uid); - -diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h -index 9465b9b4b0..6a94450450 100644 ---- a/openair2/RRC/NR/nr_rrc_proto.h -+++ b/openair2/RRC/NR/nr_rrc_proto.h -@@ -79,6 +79,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco - int scg_id, - int servCellIndex, - int dl_antenna_ports, -+ int ul_antenna_ports, - int do_csirs, - int initial_csi_index, - int uid); -@@ -90,6 +91,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon - NR_RRCReconfiguration_IEs_t *reconfig, - NR_CellGroupConfig_t *secondaryCellGroup, - int dl_antenna_ports, -+ int ul_antenna_ports, - int do_csirs, - int initial_csi_index, - int uid); -diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c -index f9fce48f41..22e43cbb6a 100644 ---- a/openair2/RRC/NR/rrc_gNB_nsa.c -+++ b/openair2/RRC/NR/rrc_gNB_nsa.c -@@ -241,6 +241,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ - reconfig_ies, - ue_context_p->ue_context.secondaryCellGroup, - carrier->pdsch_AntennaPorts, -+ carrier->pusch_AntennaPorts, - carrier->do_CSIRS, - carrier->initial_csi_index[ue_context_p->local_uid + 1], - ue_context_p->local_uid); -@@ -250,6 +251,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ - reconfig_ies, - ue_context_p->ue_context.secondaryCellGroup, - carrier->pdsch_AntennaPorts, -+ carrier->pusch_AntennaPorts, - carrier->do_CSIRS, - carrier->initial_csi_index[ue_context_p->local_uid + 1], - ue_context_p->local_uid); -@@ -348,7 +350,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ - rrc_mac_config_req_gNB(rrc->module_id, - rrc->carrier.ssb_SubcarrierOffset, - rrc->carrier.pdsch_AntennaPorts, -- rrc->carrier.pusch_AntennaPorts, -+ rrc->carrier.pusch_AntennaPorts, - rrc->carrier.sib1_tda, - rrc->carrier.servingcellconfigcommon, - &rrc->carrier.mib, -diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c -index 980bd39c37..d03f361502 100644 ---- a/openair2/RRC/NR/rrc_gNB_reconfig.c -+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c -@@ -55,6 +55,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco - int scg_id, - int servCellIndex, - int dl_antenna_ports, -+ int ul_antenna_ports, - int do_csirs, - int initial_csi_index, - int uid) { -@@ -745,14 +746,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco - pusch_Config->codebookSubset=calloc(1,sizeof(*pusch_Config->codebookSubset)); - *pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent; - pusch_Config->maxRank=calloc(1,sizeof(*pusch_Config->maxRank)); -- *pusch_Config->maxRank= 1; -+ *pusch_Config->maxRank= ul_antenna_ports; - pusch_Config->rbg_Size=NULL; - pusch_Config->uci_OnPUSCH=NULL; - pusch_Config->tp_pi2BPSK=NULL; - - /*------------------------------TRANSFORM PRECODING- -----------------------------------------------------------------------*/ - -- uint8_t transform_precoding = NR_PUSCH_Config__transformPrecoder_disabled; -+ uint8_t transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; - - // TBD: configure this from .conf file, Dedicated params cannot yet be configured in .conf file. - // Enable this to test transform precoding enabled from dedicated config. -@@ -764,13 +765,13 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco - - if (pusch_Config->transformPrecoder == NULL) { - if (servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder != NULL) -- transform_precoding = NR_PUSCH_Config__transformPrecoder_enabled; -+ transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled; - } - else -- transform_precoding = *pusch_Config->transformPrecoder; -+ transformPrecoder = *pusch_Config->transformPrecoder; - - -- if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled ) { -+ if (transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled ) { - /* Enable DMRS uplink config for transform precoding enabled */ - NR_DMRS_UplinkConfig->transformPrecodingEnabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingEnabled)); - NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity = NULL; -@@ -1348,6 +1349,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon - NR_RRCReconfiguration_IEs_t *reconfig, - NR_CellGroupConfig_t *secondaryCellGroup, - int dl_antenna_ports, -+ int ul_antenna_ports, - int do_csirs, - int initial_csi_index, - int uid) { -@@ -1363,6 +1365,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon - 1, - 1, - dl_antenna_ports, -+ ul_antenna_ports, - do_csirs, - initial_csi_index, - uid); -diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c -index 13945998d7..20faa86591 100644 ---- a/targets/ARCH/rfsimulator/simulator.c -+++ b/targets/ARCH/rfsimulator/simulator.c -@@ -429,7 +429,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp - if (!alreadyLocked) - pthread_mutex_lock(&Sockmutex); - -- LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); -+ LOG_D(HW,"sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt); - - for (int i=0; ibuf[i]; -@@ -623,7 +623,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest - } - - rfsimulator_state_t *t = device->priv; -- LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps); -+ LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld, nbAnt %d\n", nsamps, t->nextTimestamp+nsamps, nbAnt); - // deliver data from received data - // check if a UE is connected - int first_sock; -@@ -728,6 +728,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest - - for (int a=0; achannel_model != NULL ) // apply a channel model -+ { - rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a], - a, - ptr->channel_model, -@@ -735,11 +736,21 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest - t->nextTimestamp, - CirSize - ); -- else { // no channel modeling -+ } -+ else -+ { // no channel modeling -+ -+ #if 0 - double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 - {0.5, 1.0, 0.5, 0.25}, //rx 1 - {0.25, 0.5, 1.0, 0.5}, //rx 2 - {0.125, 0.25, 0.5, 1.0}};//rx 3 -+ #else -+ double H_awgn_mimo[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 -+ {0.0, 1.0, 0.0, 0.0},//rx 1 -+ {0.0, 0.0, 1.0, 0.0},//rx 2 -+ {0.0, 0.0, 0.0, 1.0}};//rx 3 -+ #endif - - sample_t *out=(sample_t *)samplesVoid[a]; - int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 8314c83ad9..f41b51161b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1969,9 +1969,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->cl_done = 0; bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start)*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; - LOG_I(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); - LOG_I(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); - LOG_I(PHY,"ulsch RX %x : start_rb %d nb_rb %d mcs %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_ports %d\n", + LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); + LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); + LOG_D(PHY,"ulsch RX %x : start_rb %d nb_rb %d mcs %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_ports %d\n", rel15_ul->rnti,rel15_ul->rb_start,rel15_ul->rb_size,rel15_ul->mcs_index, rel15_ul->nrOfLayers,0,rel15_ul->bwp_start,0,rel15_ul->start_symbol_index,rel15_ul->nr_of_symbols, rel15_ul->num_dmrs_cdm_grps_no_data,rel15_ul->ul_dmrs_symb_pos,rel15_ul->dmrs_ports); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 5d76e654ba..eda1711f6b 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -98,7 +98,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t thread_id, int gNB_id) { - LOG_I(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); + LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); uint32_t available_bits; uint8_t cwd_index, l; @@ -150,7 +150,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; - LOG_I(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", + LOG_D(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); // TbD num_of_mod_symbols is set but never used diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 63c708e565..d77fb94bc1 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -253,17 +253,17 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { // if all segments are done if (rdata->nbSegments == ulsch_harq->processedSegments) { if (decodeSuccess) { - LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", + LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); ulsch_harq->status = SCH_IDLE; ulsch_harq->round = 0; ulsch->harq_mask &= ~(1 << rdata->harq_pid); - LOG_I(PHY, "ULSCH received ok \n"); + LOG_D(PHY, "ULSCH received ok \n"); nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); //dumpsig=1; } else { - LOG_I(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, TBS %d) r %d\n", + LOG_D(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, TBS %d) r %d\n", gNB->Mod_id, ulsch_harq->frame, ulsch_harq->slot, rdata->harq_pid, pusch_pdu->pusch_data.new_data_indicator, ulsch_harq->status, ulsch_harq->round, @@ -281,7 +281,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { } ulsch_harq->handled = 1; - LOG_I(PHY, "ULSCH %d in error\n",rdata->ulsch_id); + LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1,0); } /* @@ -739,7 +739,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { (ulsch_harq->slot == slot_rx) && (ulsch_harq->handled == 0)){ - LOG_I(PHY, "PUSCH detection started in frame %d slot %d\n", + LOG_D(PHY, "PUSCH detection started in frame %d slot %d\n", frame_rx,slot_rx); int num_dmrs=0; for (int s=0;srx_pusch_stats); no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); if (no_sig) { - LOG_I(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); + LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); return 1; } @@ -791,7 +791,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot) + gNB->pusch_thres) { NR_gNB_SCH_STATS_t *stats=get_ulsch_stats(gNB,ulsch); - LOG_I(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, + LOG_D(PHY, "PUSCH not detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot), dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres); gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot; diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index d24b90ab3c..d602e38b4b 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -158,7 +158,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ for (i = 0; i < ul_config->number_pdus; ++i){ AssertFatal(ul_config->ul_config_list[i].pdu_type <= FAPI_NR_UL_CONFIG_TYPES,"pdu_type %d out of bounds\n",ul_config->ul_config_list[i].pdu_type); - LOG_I(PHY, "In %s i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); + LOG_D(PHY, "In %s i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n", __FUNCTION__, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config); uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type, current_harq_pid, gNB_id = 0; /* PRACH */ @@ -182,7 +182,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &harq_process_ul_ue->pusch_pdu; - LOG_I(PHY, "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n", __FUNCTION__, i, pusch_config_pdu->nrOfLayers,pusch_config_pdu->num_dmrs_cdm_grps_no_data); + LOG_D(PHY, "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n", __FUNCTION__, i, pusch_config_pdu->nrOfLayers,pusch_config_pdu->num_dmrs_cdm_grps_no_data); memcpy(pusch_pdu, pusch_config_pdu, sizeof(nfapi_nr_ue_pusch_pdu_t)); From 2f7e7b9823c29d517a49ddc4b44d9b8b5dc01dd4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 10 Dec 2021 10:54:10 +0100 Subject: [PATCH 018/226] remove some more logs --- cmake_targets/autotests/test_case_list.xml | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 00fcfc4140..6c9508b736 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1331,7 +1331,7 @@ -n100 -m9 -r106 -s10 -W2 -y2 -z2 -n100 -m9 -r106 -s13 -W4 -y4 -z4 - nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test16 + nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 PUSCH test OK segmentation fault|assertion|exiting|fatal 3 diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 05c1318814..84989ee6dc 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -346,7 +346,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf } long *max_length = NULL; long *dmrs_type = NULL; - LOG_I(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); + LOG_D(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) { max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength; @@ -357,7 +357,8 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type; } - LOG_I(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); + LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n", + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC @@ -509,7 +510,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME } } - LOG_I(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); + LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); } // Configuration of Msg3 PDU according to clauses: @@ -916,7 +917,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id); if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) - LOG_I(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); + LOG_D(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); mac->if_module->scheduled_response(&scheduled_response); } else { @@ -1030,7 +1031,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, rx_frame, rx_slot, ul_info->thread_id); if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){ - LOG_I(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); + LOG_D(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); mac->if_module->scheduled_response(&scheduled_response); } pthread_mutex_lock(&ul_config->mutex_ul_config); From 34866293c1485a612e9e62c4c777d2234b0b3dc5 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 11 Dec 2021 17:32:09 +0100 Subject: [PATCH 019/226] minor changes --- openair1/PHY/CODING/crc_byte.c | 4 ++-- openair2/LAYER2/NR_MAC_gNB/config.c | 4 +--- targets/ARCH/AW2SORI/oaiori.c | 5 ++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index c3b141db8e..a0ad837e87 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -153,7 +153,7 @@ unsigned int crc24a (unsigned char * inptr, { int octetlen = bitlen / 8; /* Change in octets */ - if ( bitlen % 8 || !__builtin_cpu_supports ("pclmul") ) { + if ( bitlen % 8 /*|| !__builtin_cpu_supports ("pclmul")*/ ) { unsigned int crc = 0; int resbit = (bitlen % 8); @@ -187,7 +187,7 @@ unsigned int crc24b (unsigned char * inptr, { int octetlen = bitlen / 8; /* Change in octets */ - if ( bitlen % 8 || !__builtin_cpu_supports ("pclmul") ) { + if ( bitlen % 8 /*|| !__builtin_cpu_supports ("pclmul") */) { unsigned int crc = 0; int resbit = (bitlen % 8); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 1cb3fdb708..4687f6aeea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -325,8 +325,6 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts } else { ssb_SubcarrierOffset_limit = 12; } - if (ssb_SubcarrierOffsetssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; @@ -334,7 +332,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG; cfg->num_tlv++; - cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset; + cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset>>(cfg->ssb_config.scs_common.value); cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; diff --git a/targets/ARCH/AW2SORI/oaiori.c b/targets/ARCH/AW2SORI/oaiori.c index f79e2fad20..ec69e27135 100644 --- a/targets/ARCH/AW2SORI/oaiori.c +++ b/targets/ARCH/AW2SORI/oaiori.c @@ -317,7 +317,10 @@ int aw2s_startstreaming(openair0_device *device) { (openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) || tx0->fst != ORI_FST_Operational || (openair0_cfg->tx_num_channels > 1 && tx1->fst != ORI_FST_Operational)) - {} + { + printf("rx0->fst %d,rx1->fst %d,tx0->fst %d, tx1->fst %d\n", + rx0->fst,rx1 ? rx1->fst : -1, tx0->fst, tx1 ? tx1->fst: -1); + } // test RX interface uint64_t TS; From 171408bc4d3b02a8b42b5755434fd1ff7daaf42d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 13 Dec 2021 21:25:38 +0100 Subject: [PATCH 020/226] pucch DTX threshold modification --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 4921a79fa5..ea926d0bbb 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -400,7 +400,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->pucch0_thres = gNB->pucch0_thres; /* + (10*max_n0);*/ bool no_conf=false; if (nr_sequences>1) { - if (xrtmag_dBtimes10 < (50+xrtmag_next_dBtimes10) || SNRtimes10 < uci_stats->pucch0_thres) + if (/*xrtmag_dBtimes10 < (30+xrtmag_next_dBtimes10) ||*/ SNRtimes10 < uci_stats->pucch0_thres) no_conf=true; } gNB->bad_pucch += no_conf; @@ -431,7 +431,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); uci_pdu->harq->harq_list[0].harq_value = !(index&0x01); - LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { @@ -450,7 +450,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_list[1].harq_value = !(index&0x01); uci_pdu->harq->harq_list[0].harq_value = !((index>>1)&0x01); - LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", + if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); From 99e006f750d08ad2fe25ba492046cc97e265fd9e Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 15 Dec 2021 13:38:00 +0100 Subject: [PATCH 021/226] testing with UM/No Harq --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 5 +++-- openair2/GNB_APP/gnb_config.c | 2 ++ openair2/GNB_APP/gnb_paramdef.h | 6 ++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 21 +++++++------------ openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 1 + openair2/RRC/NR/rrc_gNB.c | 3 ++- 11 files changed, 28 insertions(+), 27 deletions(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index b17fced7b7..436271fc0b 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -64,7 +64,7 @@ #define CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER "dl_bler_target_lower" #define CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD "dl_rd2_bler_threshold" #define CONFIG_STRING_MACRLC_DL_MAX_MCS "dl_max_mcs" - +#define CONFIG_STRING_MACRLC_HARQ_ROUND_MAX "harq_round_max" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -97,6 +97,7 @@ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase DL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD, "Threshold of RD2/RETX2 BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.01, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_MAX_MCS, "Maximum DL MCS that should be used", 0, u8ptr:NULL, defintval:28, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_HARQ_ROUND_MAX, "Maximum number of HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0} \ } #define MACRLC_CC_IDX 0 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 @@ -124,6 +125,6 @@ #define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 #define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24 #define MACRLC_DL_MAX_MCS_IDX 25 - +#define MACRLC_HARQ_ROUND_MAX_IDX 26 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index dffced1374..7f85164140 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -759,6 +759,7 @@ void RCconfig_nr_macrlc() { RC.nrmac[j]->dl_bler_target_lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr); RC.nrmac[j]->dl_rd2_bler_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_RD2_BLER_THRESHOLD_IDX].dblptr); RC.nrmac[j]->dl_max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr); + RC.nrmac[j]->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_HARQ_ROUND_MAX_IDX].u8ptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; LOG_I(NR_MAC,"Blacklisted PRBS %d\n",num_prbbl); memcpy(RC.nrmac[j]->ulprbbl,prbbl,275*sizeof(prbbl[0])); @@ -1041,6 +1042,7 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr); + rrc->um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr); if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) { } else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) { diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index bf1d12825e..94e9735a31 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -121,7 +121,7 @@ typedef enum { #define GNB_CONFIG_STRING_NRCELLID "nr_cellid" #define GNB_CONFIG_STRING_MINRXTXTIMEPDSCH "min_rxtxtime_pdsch" #define GNB_CONFIG_STRING_ULPRBBLACKLIST "ul_prbblacklist" - +#define GNB_CONFIG_STRING_UMONDEFAULTDRB "um_on_default_drb" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ @@ -149,7 +149,8 @@ typedef enum { {GNB_CONFIG_STRING_DOCSIRS, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ {GNB_CONFIG_STRING_MINRXTXTIMEPDSCH, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ -{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0} \ +{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0}, \ +{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0} \ } #define GNB_GNB_ID_IDX 0 @@ -174,6 +175,7 @@ typedef enum { #define GNB_NRCELLID_IDX 19 #define GNB_MINRXTXTIMEPDSCH_IDX 20 #define GNB_ULPRBBLACKLIST_IDX 21 +#define GNB_UMONDEFAULTDRB_IDX 22 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define GNBPARAMS_CHECK { \ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d8b168ae75..3f93f79621 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -611,7 +611,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* Find a free CCE */ bool freeCCE = find_free_CCE(module_id, slot, UE_id); if (!freeCCE) { - LOG_D(MAC, "%4d.%2d could not find CCE for DL DCI retransmission UE %d/RNTI %04x\n", + LOG_I(MAC, "%4d.%2d allocate_dl_transmission: could not find CCE for DL DCI retransmission UE %d/RNTI %04x\n", frame, slot, UE_id, UE_info->rnti[UE_id]); return false; } @@ -746,7 +746,7 @@ void pf_dl(module_id_t module_id, /* Find a free CCE */ bool freeCCE = find_free_CCE(module_id, slot, UE_id); if (!freeCCE) { - LOG_D(NR_MAC, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, UE_id, rnti); + LOG_I(NR_MAC, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, UE_id, rnti); continue; } /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ @@ -963,7 +963,7 @@ void nr_schedule_ue_spec(module_id_t module_id, harq->is_waiting = true; UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; - LOG_D(NR_MAC, + LOG_I(NR_MAC, "%4d.%2d [DLSCH/PDSCH/PUCCH] UE %d RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) PUCCH allocation %d TPC %d\n", frame, slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index ee312f51a0..9b48feab9d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -576,7 +576,7 @@ static void handle_dl_harq(module_id_t mod_id, add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); harq->round = 0; harq->ndi ^= 1; - } else if (harq->round >= MAX_HARQ_ROUNDS - 1) { + } else if (harq->round >= RC.nrmac[mod_id]->harq_round_max - 1) { add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); harq->round = 0; harq->ndi ^= 1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 1d6edfe4f0..b2d2b51a30 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -550,7 +550,7 @@ void handle_nr_ul_harq(const int CC_idP, remove_front_nr_list(&sched_ctrl->feedback_ul_harq); sched_ctrl->ul_harq_processes[harq_pid].is_waiting = false; - if(sched_ctrl->ul_harq_processes[harq_pid].round >= MAX_HARQ_ROUNDS - 1) { + if(sched_ctrl->ul_harq_processes[harq_pid].round >= gNB_mac->harq_round_max - 1) { abort_nr_ul_harq(mod_id, UE_id, harq_pid); } else { sched_ctrl->ul_harq_processes[harq_pid].round++; @@ -571,7 +571,7 @@ void handle_nr_ul_harq(const int CC_idP, harq_pid, crc_pdu->rnti); add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); - } else if (harq->round >= MAX_HARQ_ROUNDS - 1) { + } else if (harq->round >= gNB_mac->harq_round_max - 1) { abort_nr_ul_harq(mod_id, UE_id, harq_pid); LOG_D(NR_MAC, "RNTI %04x: Ulharq id %d crc failed in all rounds\n", @@ -1481,7 +1481,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) sched_ctrl->last_ul_frame = sched_pusch->frame; sched_ctrl->last_ul_slot = sched_pusch->slot; - LOG_D(NR_MAC, + LOG_I(NR_MAC, "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", frame, slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 738f9b4117..5091262a0b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -781,6 +781,7 @@ typedef struct gNB_MAC_INST_s { double dl_bler_target_lower; double dl_rd2_bler_threshold; uint8_t dl_max_mcs; + uint8_t harq_round_max; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ff6923429e..f1cc264b9f 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1258,7 +1258,7 @@ void fill_initial_SpCellConfig(rnti_t rnti, ss2->nrofCandidates=calloc(1,sizeof(*ss2->nrofCandidates)); ss2->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; ss2->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2; - ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; + ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0; ss2->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; ss2->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; ss2->searchSpaceType=calloc(1,sizeof(*ss2->searchSpaceType)); @@ -1317,7 +1317,7 @@ void fill_initial_SpCellConfig(rnti_t rnti, } -void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup) { +void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup,int use_rlc_um_for_drb) { cellGroupConfig->cellGroupId = 0; cellGroupConfig->rlc_BearerToReleaseList = NULL; @@ -1377,18 +1377,11 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr rlc_BearerConfig_drb->servedRadioBearer->choice.drb_Identity = 1; rlc_BearerConfig_drb->reestablishRLC = NULL; rlc_Config_drb = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config_drb->present = NR_RLC_Config_PR_am; - rlc_Config_drb->choice.am = calloc(1, sizeof(*rlc_Config_drb->choice.am)); - rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; - rlc_Config_drb->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms80; - rlc_Config_drb->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms10; - rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; - rlc_Config_drb->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms80; - rlc_Config_drb->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; - rlc_Config_drb->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB125; - rlc_Config_drb->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; + + if (use_rlc_um_for_drb) nr_drb_config(rlc_Config_drb, NR_RLC_Config_PR_um_Bi_Directional); + else nr_drb_config(rlc_Config_drb, NR_RLC_Config_PR_am); + + rlc_BearerConfig_drb->rlc_Config = rlc_Config_drb; logicalChannelConfig_drb = calloc(1, sizeof(NR_LogicalChannelConfig_t)); logicalChannelConfig_drb->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters)); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 7b38de2bb9..b9a3ea6dac 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -99,7 +99,7 @@ void fill_initial_cellGroupConfig(rnti_t rnti, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier); -void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup); +void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup,int use_rlc_um_for_drb); uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, uint8_t *const buffer, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index ad31e8cac7..95f3772b71 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -514,6 +514,7 @@ typedef struct gNB_RRC_INST_s { int srb1_max_retx_threshold; int srb1_timer_reordering; int srb1_timer_status_prohibit; + int um_on_default_drb; int srs_enable[MAX_NUM_CCs]; uint16_t sctp_in_streams; uint16_t sctp_out_streams; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 65ae2660b3..2ff3da787c 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1109,7 +1109,8 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( memset(buffer, 0, RRC_BUF_SIZE); cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup); + fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup, + rrc->um_on_default_drb); size = do_RRCReconfiguration(ctxt_pP, buffer, xid, *SRB_configList2, From 50629a83a22ef75b79ef8e290c7f0db358cb270b Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 20 Dec 2021 21:24:52 +0100 Subject: [PATCH 022/226] first set of changes to AW2S ORI/eCPRI driver for n78 --- targets/ARCH/AW2SORI/oaiori.c | 44 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/targets/ARCH/AW2SORI/oaiori.c b/targets/ARCH/AW2SORI/oaiori.c index f79e2fad20..ea39d9c90d 100644 --- a/targets/ARCH/AW2SORI/oaiori.c +++ b/targets/ARCH/AW2SORI/oaiori.c @@ -101,31 +101,37 @@ static const eutra_bandentry_t eutra_bandtable[] = { uint32_t to_earfcn_DL_aw2s(int eutra_bandP, long long int dl_CarrierFreq, uint32_t bw) { uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq / 100000; - int i; + int i=0; if (eutra_bandP > 68) { printf("eutra_band %d > 68\n", eutra_bandP); exit(-1);} - for (i = 0; i < BANDTABLE_SIZE && eutra_bandtable[i].band != eutra_bandP; i++); - printf("AW2S: band %d, index %d\n",eutra_bandP, i); + + if (eutra_bandP > 0) + for (i = 0; i < BANDTABLE_SIZE && eutra_bandtable[i].band != eutra_bandP; i++); + printf("AW2S: band %d: index %d\n",eutra_bandP, i); if (i >= BANDTABLE_SIZE) { printf(" i = %d , it will trigger out-of-bounds read.\n",i); exit(-1);} - if (dl_CarrierFreq_by_100k < eutra_bandtable[i].dl_min) { - printf("Band %d, bw %u : DL carrier frequency %u .1 MHz < %u\n", - eutra_bandP, bw, dl_CarrierFreq_by_100k, - eutra_bandtable[i].dl_min); exit(-1);} + while(i - (eutra_bandtable[i].dl_max - bw)) { - printf("Band %d, bw %u : DL carrier frequency %u .1MHz > %d\n", - eutra_bandP, bw, dl_CarrierFreq_by_100k, - eutra_bandtable[i].dl_max - bw); exit(-1); } - printf("AW2S: dl_CarrierFreq_by_100k %d, dl_min %d\n",dl_CarrierFreq_by_100k,eutra_bandtable[i].dl_min); + if(dl_CarrierFreq_by_100k > + (eutra_bandtable[i].dl_max - bw)) { + printf("Band %d, bw %u : DL carrier frequency %u .1MHz > %d\n", + eutra_bandtable[i].band, bw, dl_CarrierFreq_by_100k, + eutra_bandtable[i].dl_max - bw); i++;continue; } + printf("AW2S: dl_CarrierFreq_by_100k %d, dl_min %d\n",dl_CarrierFreq_by_100k,eutra_bandtable[i].dl_min); - return (dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + - (eutra_bandtable[i].N_OFFs_DL / 10)); + return (dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + + (eutra_bandtable[i].N_OFFs_DL / 10)); + + } + printf("No DL band found\n"); + exit(-1); } - uint32_t to_earfcn_UL_aw2s(int eutra_bandP, long long int ul_CarrierFreq, uint32_t bw) { uint32_t ul_CarrierFreq_by_100k = ul_CarrierFreq / 100000; int i; @@ -134,6 +140,7 @@ uint32_t to_earfcn_UL_aw2s(int eutra_bandP, long long int ul_CarrierFreq, uint32 exit(-1); } + for (i = 0; i < BANDTABLE_SIZE && eutra_bandtable[i].band != eutra_bandP; i++); if(i >= BANDTABLE_SIZE) {printf("i = %d , it will trigger out-of-bounds read.\n",i); exit(-1);} @@ -313,12 +320,13 @@ int aw2s_startstreaming(openair0_device *device) { printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); } + /* while (rx0->fst != ORI_FST_Operational || (openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) || tx0->fst != ORI_FST_Operational || (openair0_cfg->tx_num_channels > 1 && tx1->fst != ORI_FST_Operational)) {} - +*/ // test RX interface uint64_t TS; char temp_rx[1024] __attribute__((aligned(32))); @@ -475,7 +483,7 @@ int aw2s_oriinit(openair0_device *device) { txParams.TxEUtraTDD.axcW = 1; txParams.TxEUtraTDD.axcB = 0; txParams.TxEUtraTDD.chanBW = openair0_cfg->tx_bw/100e3; - txParams.TxEUtraTDD.earfcn = to_earfcn_DL_aw2s(38,(long long int)openair0_cfg->tx_freq[0],txParams.TxEUtraTDD.chanBW); + txParams.TxEUtraTDD.earfcn = to_earfcn_DL_aw2s(-1,(long long int)openair0_cfg->tx_freq[0],txParams.TxEUtraTDD.chanBW); txParams.TxEUtraTDD.maxTxPwr = 430-((int)openair0_cfg->tx_gain[0]*10); txParams.TxEUtraTDD.tddULDLConfig = 1; txParams.TxEUtraTDD.tddSpecialSFConfig = 0; From 882c4b34a2a43a26f62994dc3673b217d94e8783 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 7 Jan 2022 18:03:35 +0100 Subject: [PATCH 023/226] cleanup --- openair1/PHY/INIT/nr_init.c | 11 +-- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 21 ++--- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 18 ++--- .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 8 -- openair1/SIMULATION/NR_PHY/ulsim.c | 80 ++----------------- 5 files changed, 24 insertions(+), 114 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 2ac3230215..2beda80d36 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -284,10 +284,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear( NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); - for (int j=0; j< max_ul_mimo_layers; j++) - { - for (int k=0; krho[i][j*max_ul_mimo_layers+k]=(int32_t *)malloc16_clear( sizeof(int32_t) * fp->N_RB_UL*12*7*2 ); } } @@ -303,11 +301,10 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); } - for (i=0; i< max_ul_mimo_layers; i++) - { + for (i=0; i< max_ul_mimo_layers; i++) { pusch_vars[ULSCH_id]->llr_layers[i] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear } pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 3ea19a9970..6bfcc1d50c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -145,25 +145,20 @@ void nr_ulsch_layer_demapping(int16_t *llr_cw, { switch (Nl) { - case 1: memcpy((void*)llr_cw, (void*)llr_layers[0], (length)*sizeof(int16_t)); - break; - + break; case 2: case 3: case 4: - for (int i=0; i<(length/Nl/mod_order); i++) - { - for (int l=0; lnb_antennas_rx; aarx++) - { + for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 - if (is_dmrs_symbol == 0) - { + if (is_dmrs_symbol == 0) { // //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) @@ -466,14 +464,10 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, int off = 0; #endif -for (aatx = 0; aatx < nrOfLayers; aatx++) -{ - for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) - { + for (aatx = 0; aatx < nrOfLayers; aatx++) { + for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) { ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))]; - - for (rb=0;rb < nb_rb_0;rb++) - { + for (rb=0;rb < nb_rb_0;rb++) { ul_ch128[0] = _mm_mulhi_epi16(ul_ch128[0], ch_amp128); ul_ch128[0] = _mm_slli_epi16(ul_ch128[0], 3); @@ -484,8 +478,8 @@ for (aatx = 0; aatx < nrOfLayers; aatx++) ul_ch128[2] = _mm_slli_epi16(ul_ch128[2], 3); ul_ch128+=3; } + } } -} #endif } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index a293eec6d8..036c1deaa6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -259,14 +259,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, Tbslbrm = 950984; //max tbs Coderate = 0.0; - #if 0 - harq_process->a[0] = 0x31; - for (int i = 1; i < harq_process->pusch_pdu.pusch_data.tb_size; i++) - { - harq_process->a[i] = (i&0xff); - } - #endif - trace_NRpdu(DIRECTION_UPLINK, harq_process->a, harq_process->pusch_pdu.pusch_data.tb_size, 0, WS_C_RNTI, 0, 0, 0,0, 0); /////////// ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 957a624800..6caa18ae33 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -488,32 +488,26 @@ int main(int argc, char **argv) case 'y': n_tx = atoi(optarg); - if ((n_tx == 0) || (n_tx > 4)) { - printf("Unsupported number of tx antennas %d\n", n_tx); - exit(-1); + printf("Unsupported number of tx antennas %d\n", n_tx); + exit(-1); } - break; case 'z': n_rx = atoi(optarg); - if ((n_rx == 0) || (n_rx > 8)) { - printf("Unsupported number of rx antennas %d\n", n_rx); - exit(-1); + printf("Unsupported number of rx antennas %d\n", n_rx); + exit(-1); } - break; case 'F': input_fd = fopen(optarg, "r"); - if (input_fd == NULL) { - printf("Problem with filename %s\n", optarg); - exit(-1); + printf("Problem with filename %s\n", optarg); + exit(-1); } - break; case 'G': @@ -571,13 +565,10 @@ int main(int argc, char **argv) break; case 'Z': - transformPrecoder = transformPrecoder_enabled; num_dmrs_cdm_grps_no_data = 2; mcs_table = 3; - printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transformPrecoder); - break; default: @@ -1300,15 +1291,6 @@ int main(int argc, char **argv) ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); - #if 0 - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i])); // convert to fixed point - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i])); - - - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) ] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i) ]; // convert to fixed point - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1] = ((int16_t*) &UE->common_vars.txdata[ap][slot_offset])[(2*i)+1 ]; - #endif - /* Add phase noise if enabled */ if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)], @@ -1451,56 +1433,6 @@ int main(int argc, char **argv) &gNB->pusch_vars[0]->llr_layers[3][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); } - #if 0 - if (n_rx == 2) { - LOG_MM("rxsigF0_comp.m","rxsF1_comp", - &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_ext.m","rxsF1_ext", - &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chestF0_ext.m","chF1_ext", - &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagF0.m","chmF1", - &gNB->pusch_vars[0]->ul_ch_mag[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagbF0.m","chmbF1", - &gNB->pusch_vars[0]->ul_ch_magb[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - } else if (n_rx == 4) { - LOG_MM("rxsigF0_comp.m","rxsF1_comp", - &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_comp.m","rxsF2_comp", - &gNB->pusch_vars[0]->rxdataF_comp[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_comp.m","rxsF3_comp", - &gNB->pusch_vars[0]->rxdataF_comp[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_ext.m","rxsF1_ext", - &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_ext.m","rxsF2_ext", - &gNB->pusch_vars[0]->rxdataF_ext[2][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("rxsigF0_ext.m","rxsF3_ext", - &gNB->pusch_vars[0]->rxdataF_ext[3][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chestF0_ext.m","chF1_ext", - &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chestF0_ext.m","chF2_ext", - &gNB->pusch_vars[0]->ul_ch_estimates_ext[2][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chestF0_ext.m","chF3_ext", - &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagF0.m","chmF1", - &gNB->pusch_vars[0]->ul_ch_mag[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagF0.m","chmF2", - &gNB->pusch_vars[0]->ul_ch_mag[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagF0.m","chmF3", - &gNB->pusch_vars[0]->ul_ch_mag[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagbF0.m","chmbF1", - &gNB->pusch_vars[0]->ul_ch_magb[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagbF0.m","chmbF2", - &gNB->pusch_vars[0]->ul_ch_magb[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_MM("chmagbF0.m","chmbF3", - &gNB->pusch_vars[0]->ul_ch_magb[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - } - #endif - LOG_M("rxsigF0_llr.m","rxsF0_llr", &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); } From 65698f6a8f813d2a5bf53978d533f0f24db756a0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 17 Jan 2022 15:15:47 +0100 Subject: [PATCH 024/226] some improvements in ul-mimo code --- executables/nr-uesoftmodem.c | 2 - .../nfapi/public_inc/nfapi_nr_interface_scf.h | 1 - nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 2 - openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 311 ++++++++---------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 38 ++- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 4 + openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 75 ++--- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 1 - 10 files changed, 219 insertions(+), 225 deletions(-) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 1d36ff9017..ac89bcfd4e 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -493,8 +493,6 @@ int main( int argc, char **argv ) { set_options(CC_id, UE[CC_id]); NR_UE_MAC_INST_t *mac = get_mac_inst(0); - NR_DL_FRAME_PARMS *fp = &UE[CC_id]->frame_parms; - mac->phy_config.config_req.carrier_config.num_tx_ant = fp->nb_antennas_tx; if (get_softmodem_params()->sa) { // set frame config to initial values from command line and assume that the SSB is centered on the grid uint16_t nr_band = get_band(downlink_frequency[CC_id][0],uplink_frequency_offset[CC_id][0]); diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 4e8d3b9401..e3b7a55f7b 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1213,7 +1213,6 @@ typedef struct uint8_t transformPrecoder; uint16_t data_scrambling_id; uint8_t nrOfLayers; - uint8_t Tpmi; //DMRS uint16_t ul_dmrs_symb_pos; uint8_t dmrs_config_type; diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 9b844d22cf..8d83151ce8 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -950,7 +950,6 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui push8(pusch_pdu->transformPrecoder, ppWritePackedMsg, end) && push16(pusch_pdu->data_scrambling_id, ppWritePackedMsg, end) && push8(pusch_pdu->nrOfLayers, ppWritePackedMsg, end) && - push8(pusch_pdu->Tpmi, ppWritePackedMsg, end) && push16(pusch_pdu->ul_dmrs_symb_pos, ppWritePackedMsg, end) && push8(pusch_pdu->dmrs_config_type, ppWritePackedMsg, end) && push16(pusch_pdu->ul_dmrs_scrambling_id, ppWritePackedMsg, end) && @@ -4449,7 +4448,6 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(void *tlv, uint8_t **ppReadPacked pull8(ppReadPackedMsg, &pusch_pdu->transformPrecoder, end) && pull16(ppReadPackedMsg, &pusch_pdu->data_scrambling_id, end) && pull8(ppReadPackedMsg, &pusch_pdu->nrOfLayers, end) && - pull8(ppReadPackedMsg, &pusch_pdu->Tpmi, end) && pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_symb_pos, end) && pull8(ppReadPackedMsg, &pusch_pdu->dmrs_config_type, end) && pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_scrambling_id, end) && diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 9bbc61d4b6..edd997a30f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -285,7 +285,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, start_meas(&gNB->dlsch_resource_mapping_stats); for (int ap=0; apnrOfLayers; ap++) { - // DMRS params for this ap + // DMRS params for this poir get_Wt(Wt, ap, dmrs_Type); get_Wf(Wf, ap, dmrs_Type); delta = get_delta(ap, dmrs_Type); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index d174d85eac..84ad8aa8af 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -37,6 +37,7 @@ #include "PHY/MODULATION/nr_modulation.h" #include "PHY/MODULATION/modulation_common.h" #include "common/utils/assertions.h" +#include "common/utils/nr/nr_common.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" @@ -107,7 +108,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, int8_t Wf[2], Wt[2]; int l_prime[2], delta; uint8_t nb_dmrs_re_per_rb; - int ap, i; + int i; int sample_offsetF, N_RE_prime; NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; @@ -207,99 +208,99 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////// //////////////////////////////////////////////////////////////////////// - /////////////////////////DMRS Modulation///////////////////////// - /////////// - uint32_t ***pusch_dmrs = UE->nr_gold_pusch_dmrs[slot]; - uint16_t n_dmrs = (pusch_pdu->bwp_start + start_rb + nb_rb)*((dmrs_type == pusch_dmrs_type1) ? 6:4); - int16_t mod_dmrs[n_dmrs<<1] __attribute((aligned(16))); - /////////// - //////////////////////////////////////////////////////////////////////// + /////////////////////////DMRS Modulation///////////////////////// + /////////// + uint32_t ***pusch_dmrs = UE->nr_gold_pusch_dmrs[slot]; + uint16_t n_dmrs = (pusch_pdu->bwp_start + start_rb + nb_rb)*((dmrs_type == pusch_dmrs_type1) ? 6:4); + int16_t mod_dmrs[n_dmrs<<1] __attribute((aligned(16))); + /////////// + //////////////////////////////////////////////////////////////////////// - /////////////////////////PTRS parameters' initialization///////////////////////// - /////////// + /////////////////////////PTRS parameters' initialization///////////////////////// + /////////// - int16_t mod_ptrs[nb_rb] __attribute((aligned(16))); // assume maximum number of PTRS per pusch allocation - uint8_t L_ptrs, K_ptrs = 0; - uint16_t beta_ptrs = 1; // temp value until power control is implemented + int16_t mod_ptrs[nb_rb] __attribute((aligned(16))); // assume maximum number of PTRS per pusch allocation + uint8_t L_ptrs, K_ptrs = 0; + uint16_t beta_ptrs = 1; // temp value until power control is implemented - if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - K_ptrs = harq_process_ul_ue->pusch_pdu.pusch_ptrs.ptrs_freq_density; - L_ptrs = 1<pusch_pdu.pusch_ptrs.ptrs_time_density; + K_ptrs = harq_process_ul_ue->pusch_pdu.pusch_ptrs.ptrs_freq_density; + L_ptrs = 1<pusch_pdu.pusch_ptrs.ptrs_time_density; - beta_ptrs = 1; // temp value until power control is implemented + beta_ptrs = 1; // temp value until power control is implemented - ulsch_ue->ptrs_symbols = 0; + ulsch_ue->ptrs_symbols = 0; - set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, - number_of_symbols, - start_symbol, - L_ptrs, - ul_dmrs_symb_pos); - } - - /////////// - //////////////////////////////////////////////////////////////////////////////// - - /////////////////////////ULSCH layer mapping///////////////////////// - /////////// - - nr_ue_layer_mapping(UE->ulsch[thread_id][gNB_id], - Nl, - available_bits/mod_order, - tx_layers); - - /////////// - //////////////////////////////////////////////////////////////////////// - - - //////////////////////// ULSCH transform precoding //////////////////////// - /////////// - - l_prime[0] = 0; // single symbol ap 0 - - uint16_t index; - uint8_t u = 0, v = 0; - int16_t *dmrs_seq = NULL; - - // if transform precoding is enbaled (value 0) - if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { - - uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; - uint32_t y_offset = 0; - uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2); - - // Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol - index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol); - u = pusch_pdu->dfts_ofdm.low_papr_group_number; - v = pusch_pdu->dfts_ofdm.low_papr_sequence_number; - dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index]; - - AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); - AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated"); - - LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); - - for (l = start_symbol; l < start_symbol + number_of_symbols; l++) { - - if((ul_dmrs_symb_pos >> l) & 0x01) - /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ - continue; - - nr_dft(&ulsch_ue->y[y_offset], &((int32_t*)tx_layers[0])[y_offset], nb_re_pusch); - - y_offset = y_offset + nb_re_pusch; - - LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset); - - #ifdef DEBUG_PUSCH_MAPPING - printf("NR_ULSCH_UE: y_offset %d\t nb_re_pusch %d \t Symbol %d \t nb_rb %d \n", - y_offset, nb_re_pusch, l, nb_rb); - #endif + set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, + number_of_symbols, + start_symbol, + L_ptrs, + ul_dmrs_symb_pos); } - #ifdef DEBUG_DFT_IDFT + /////////// + //////////////////////////////////////////////////////////////////////////////// + + /////////////////////////ULSCH layer mapping///////////////////////// + /////////// + + nr_ue_layer_mapping(UE->ulsch[thread_id][gNB_id], + Nl, + available_bits/mod_order, + tx_layers); + + /////////// + //////////////////////////////////////////////////////////////////////// + + + //////////////////////// ULSCH transform precoding //////////////////////// + /////////// + + l_prime[0] = 0; // single symbol ap 0 + + uint16_t index; + uint8_t u = 0, v = 0; + int16_t *dmrs_seq = NULL; + + // if transform precoding is enbaled (value 0) + if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { + + uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; + uint32_t y_offset = 0; + uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2); + + // Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol + index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol); + u = pusch_pdu->dfts_ofdm.low_papr_group_number; + v = pusch_pdu->dfts_ofdm.low_papr_sequence_number; + dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index]; + + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated"); + + LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); + + for (l = start_symbol; l < start_symbol + number_of_symbols; l++) { + + if((ul_dmrs_symb_pos >> l) & 0x01) + /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ + continue; + + nr_dft(&ulsch_ue->y[y_offset], &((int32_t*)tx_layers[0])[y_offset], nb_re_pusch); + + y_offset = y_offset + nb_re_pusch; + + LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset); + + #ifdef DEBUG_PUSCH_MAPPING + printf("NR_ULSCH_UE: y_offset %d\t nb_re_pusch %d \t Symbol %d \t nb_rb %d \n", + y_offset, nb_re_pusch, l, nb_rb); + #endif + } + + #ifdef DEBUG_DFT_IDFT int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__ ((aligned(16))); int offset = 0; printf("NR_ULSCH_UE: available_bits: %d, mod_order: %d", available_bits,mod_order); @@ -320,20 +321,19 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_M("postDFT_all_symbols.m","UE_postDFT", ulsch_ue->y,number_of_symbols*nb_re_pusch,1,1); LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1); LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); - #endif + #endif - } + } - /////////// - //////////////////////////////////////////////////////////////////////// + /////////// + //////////////////////////////////////////////////////////////////////// - /////////////////////////ULSCH RE mapping///////////////////////// - /////////// + /////////////////////////ULSCH RE mapping///////////////////////// + /////////// - for (ap=0; ap< Nl; ap++) - { + for (int l=0; l < Nl; l++) { uint8_t k_prime = 0; uint16_t m = 0; @@ -341,24 +341,22 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); #endif - // DMRS params for this ap - get_Wt(Wt, ap, dmrs_type); - get_Wf(Wf, ap, dmrs_type); - delta = get_delta(ap, dmrs_type); + int dmrs_port = get_dmrs_port(l,pusch_pdu->dmrs_ports); + // DMRS params for this dmrs port + get_Wt(Wt, dmrs_port, dmrs_type); + get_Wf(Wf, dmrs_port, dmrs_type); + delta = get_delta(dmrs_port, dmrs_type); - for (l=start_symbol; l> l) & 0x01) - { + if ((ul_dmrs_symb_pos >> l) & 0x01) { is_dmrs_sym = 1; - if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) - { + if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { if (dmrs_type == pusch_dmrs_type1) dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; else @@ -369,39 +367,33 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY,"DMRS in symbol %d\n",l); nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated } - else - { + else { dmrs_idx = 0; } } - else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) - { + else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { AssertFatal(pusch_pdu->transformPrecoder == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); - if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) - { + if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { is_ptrs_sym = 1; nr_modulation(pusch_dmrs[l][0], nb_rb, DMRS_MOD_ORDER, mod_ptrs); } } - for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) - { + for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) { uint8_t is_dmrs = 0; uint8_t is_ptrs = 0; sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - if (is_dmrs_sym) - { + if (is_dmrs_sym) { if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) is_dmrs = 1; } - else if (is_ptrs_sym) - { + else if (is_ptrs_sym) { is_ptrs = is_ptrs_subcarrier(k, rnti, - ap, + dmrs_port, dmrs_type, K_ptrs, nb_rb, @@ -410,23 +402,20 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, frame_parms->ofdm_symbol_size); } - if (is_dmrs == 1) - { - if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; + if (is_dmrs == 1) { + if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; } - else - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; + else { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; } #ifdef DEBUG_PUSCH_MAPPING printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", - ap, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); + l, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1]); #endif dmrs_idx++; @@ -434,47 +423,41 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, k_prime&=1; n+=(k_prime)?0:1; } - else if (is_ptrs == 1) - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; + else if (is_ptrs == 1) { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; ptrs_idx++; } - else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) - { - if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[ap])[m<<1]; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[ap])[(m<<1) + 1]; + else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { + if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[l])[m<<1]; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[l])[(m<<1) + 1]; } - else - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; + else { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; } #ifdef DEBUG_PUSCH_MAPPING printf("DATA: layer %d\t m %d\t l %d \t k %d \t txdataF: %d %d\n", - ap, m, l, k, ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1], - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1]); + l, m, l, k, ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1]); #endif m++; } - else - { - ((int16_t*)tx_precoding[ap])[(sample_offsetF)<<1] = 0; - ((int16_t*)tx_precoding[ap])[((sample_offsetF)<<1) + 1] = 0; + else { + ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = 0; + ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = 0; } - if (++k >= frame_parms->ofdm_symbol_size) - { + if (++k >= frame_parms->ofdm_symbol_size) { k -= frame_parms->ofdm_symbol_size; } } //for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) }//for (l=start_symbol; lnb_antennas_tx; ap++) - { - for (int l=start_symbol; lnb_antennas_tx; ap++) { + for (int l=start_symbol; lTpmi; @@ -510,12 +490,10 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, k -= frame_parms->ofdm_symbol_size; } } - else - { + else { //get the precoding matrix weights: char *W_prec; - switch (frame_parms->nb_antennas_tx) - { + switch (frame_parms->nb_antennas_tx) { case 1://1 antenna port W_prec = nr_W_1l_2p[pmi][ap]; break; @@ -541,15 +519,13 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, break; } - for (int i=0; iofdm_symbol_size + k; int32_t precodatatx_F = nr_layer_precoder(tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); ((int16_t*)txdataF[ap])[(re_offset<<1)] = ((int16_t *) &precodatatx_F)[0]; ((int16_t*)txdataF[ap])[(re_offset<<1) + 1] = ((int16_t *) &precodatatx_F)[1]; - if (++k >= frame_parms->ofdm_symbol_size) - { + if (++k >= frame_parms->ofdm_symbol_size) { k -= frame_parms->ofdm_symbol_size; } } @@ -557,7 +533,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, } //RB loop } // symbol loop }// port loop - } //for (cwd_index = 0;cwd_index < num_of_codewords; cwd_index++) NR_UL_UE_HARQ_t *harq_process_ulsch=NULL; @@ -573,7 +548,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, uint8_t slot, NR_DL_FRAME_PARMS *frame_parms, - uint8_t Nl) { + uint8_t n_antenna_ports) { int tx_offset, ap; int32_t **txdata; @@ -595,7 +570,7 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, txdataF = UE->common_vars.txdataF; int symb_offset = (slot%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; - for(ap = 0; ap < Nl; ap++) { + for(ap = 0; ap < n_antenna_ports; ap++) { for (int s=0;s (%d.%d)\n", @@ -613,7 +588,7 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, } } - for (ap = 0; ap < Nl; ap++) { + for (ap = 0; ap < n_antenna_ports; ap++) { if (frame_parms->Ncp == 1) { // extended cyclic prefix PHY_ofdm_mod(txdataF[ap], &txdata[ap][tx_offset], diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 206a55347c..d185517fcc 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -369,10 +369,10 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH nr_ulsch_layer_demapping(gNB->pusch_vars[ULSCH_id]->llr, - pusch_pdu->nrOfLayers, - pusch_pdu->qam_mod_order, - G, - gNB->pusch_vars[ULSCH_id]->llr_layers); + pusch_pdu->nrOfLayers, + pusch_pdu->qam_mod_order, + G, + gNB->pusch_vars[ULSCH_id]->llr_layers); //---------------------------------------------------------- //------------------- ULSCH unscrambling ------------------- diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 7e5be9eeba..b7f928f709 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -33,6 +33,7 @@ #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "common/utils/nr/nr_common.h" #include +#include #define reserved 0xffff @@ -2531,6 +2532,30 @@ uint8_t get_transformPrecoding(const NR_BWP_UplinkCommon_t *initialUplinkBWP, return -1; } +uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator) { + + uint8_t n_antenna_port = 1; + if (get_softmodem_params()->phy_test == 1) { + // temporary hack to allow UL-MIMO in phy-test mode without SRS + n_antenna_port = *pusch_Config->maxRank; + } + else { + if(srs_config != NULL && srs_resource_indicator.nbits > 0) { + for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { + NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; + if(srs_resource_set->usage == NR_SRS_ResourceSet__usage_codebook) { + NR_SRS_Resource_t *srs_resource = srs_config->srs_ResourceToAddModList->list.array[srs_resource_indicator.val]; + AssertFatal(srs_resource != NULL,"SRS resource indicated by DCI does not exist\n"); + n_antenna_port = 1<nrofSRS_Ports; + } + } + } + } + return n_antenna_port; +} + uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, const NR_BWP_UplinkCommon_t *initialUplinkBWP, const NR_CellGroupConfig_t *cg, @@ -2544,17 +2569,16 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, uint16_t numRBG = 0; long rbg_size_config; int num_entries = 0; - int pusch_antenna_ports = 1; // TODO hardcoded number of antenna ports for pusch const NR_BWP_DownlinkDedicated_t *bwpd = NULL; const NR_BWP_UplinkDedicated_t *ubwpd = NULL; const NR_BWP_DownlinkCommon_t *bwpc = NULL; const NR_BWP_UplinkCommon_t *ubwpc = NULL; - const NR_PDSCH_Config_t *pdsch_Config = NULL; - const NR_PUSCH_Config_t *pusch_Config = NULL; - const NR_PUCCH_Config_t *pucch_Config = NULL; - const NR_PDCCH_Config_t *pdcch_Config = NULL; - const NR_SRS_Config_t *srs_config = NULL; + NR_PDSCH_Config_t *pdsch_Config = NULL; + NR_PUSCH_Config_t *pusch_Config = NULL; + NR_PUCCH_Config_t *pucch_Config = NULL; + NR_PDCCH_Config_t *pdcch_Config = NULL; + NR_SRS_Config_t *srs_config = NULL; if(bwp_id > 0) { AssertFatal(cg!=NULL,"Cellgroup is null and bwp_id!=0"); bwpd=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; @@ -2709,7 +2733,7 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, // Precoding info and number of layers long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); - pusch_antenna_ports = *pusch_Config->maxRank; + uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, dci_pdu->srs_resource_indicator); dci_pdu->precoding_information.nbits=0; if (pusch_Config && diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 8182e1c930..23c022bf0c 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -144,6 +144,10 @@ void get_info_from_tda_tables(int default_abc, void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config); void fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config); +uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator); + uint16_t compute_pucch_prb_size(uint8_t format, uint8_t nr_prbs, uint16_t O_tot, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index adb2c966b0..83981c8a6f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -44,6 +44,7 @@ /* MAC */ #include "NR_MAC_COMMON/nr_mac.h" +#include "NR_MAC_COMMON/nr_mac_common.h" #include "NR_MAC_UE/mac_proto.h" #include "NR_MAC_UE/mac_extern.h" @@ -181,13 +182,16 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con NR_ServingCellConfigCommon_t *scc = mac->scc; NR_BWP_UplinkDedicated_t *ubwpd=NULL; + NR_SRS_Config_t *srs_config = NULL; if (mac->cg && mac->cg->spCellConfig && mac->cg->spCellConfig->spCellConfigDedicated && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + srs_config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; + } NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0] ? mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup : @@ -212,7 +216,10 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)){ - uint8_t n_antenna_port = mac->phy_config.config_req.carrier_config.num_tx_ant; + // The UE shall transmit PUSCH using the same antenna port(s) as the SRS port(s) in the SRS resource indicated by the DCI format 0_1 + // 38.214 Section 6.1.1 + + uint8_t n_antenna_port = get_pusch_nb_antenna_ports(pusch_Config, srs_config, dci->srs_resource_indicator); if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits @@ -331,10 +338,9 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con } // todo: this function shall be reviewed completely because of the many comments left by the author -void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci) { +void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci) { - /* ANTENNA_PORTS */ - uint8_t rank = 1; // We need to initialize rank FIXME!!! + uint8_t rank = pusch_config_pdu->nrOfLayers; NR_ServingCellConfigCommon_t *scc = mac->scc; NR_BWP_UplinkDedicated_t *ubwpd=NULL; @@ -373,29 +379,24 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n", pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && - (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC - pusch_config_pdu->dmrs_ports = dci->antenna_ports.val; //TBC + (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + pusch_config_pdu->dmrs_ports = 1<antenna_ports.val; } if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && - (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-7 + (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-7 pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC - pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 3)?(dci->antenna_ports.val-4):(dci->antenna_ports.val); //TBC - //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports > 3)?2:1; //FIXME + pusch_config_pdu->dmrs_ports = 1<<((dci->antenna_ports.val > 3)?(dci->antenna_ports.val-4):(dci->antenna_ports.val)); + *n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; } if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && - (dmrs_type == NULL) && (max_length == NULL)) - { // tables 7.3.1.1.2-8/9/10/11 + (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11 - if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)) - { - rank = pusch_config_pdu->nrOfLayers; - } - if (rank == 1) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; pusch_config_pdu->dmrs_ports =1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val)); @@ -408,12 +409,12 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf if (rank == 3){ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; - pusch_config_pdu->dmrs_ports = ((1<dmrs_ports = 0x7; // ports 0-2 } if (rank == 4){ pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; - pusch_config_pdu->dmrs_ports = ((1<dmrs_ports = 0xf; // ports 0-3 } } @@ -422,8 +423,8 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf if (rank == 1){ pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC - pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val; //TBC - //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports.val > 6)?2:1; //FIXME + pusch_config_pdu->dmrs_ports = 1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val); + *n_front_load_symb = (dci->antenna_ports.val > 6)?2:1; } if (rank == 2){ @@ -431,7 +432,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf pusch_config_pdu->dmrs_ports = 0; //FIXME //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_13[dci->antenna_ports.val][1]; //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_13[dci->antenna_ports.val][2]; - //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; // FIXME + //n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; // FIXME } if (rank == 3){ @@ -440,7 +441,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_14[dci->antenna_ports.val][1]; //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_14[dci->antenna_ports.val][2]; //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_14[dci->antenna_ports.val][3]; - //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME + //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME } if (rank == 4){ @@ -450,7 +451,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_15[dci->antenna_ports.val][2]; //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_15[dci->antenna_ports.val][3]; //pusch_config_pdu->dmrs_ports[3] = table_7_3_1_1_2_15[dci->antenna_ports.val][4]; - //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME + //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME } } @@ -494,7 +495,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf if (rank == 1){ pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_20[dci->antenna_ports.val][0]; //TBC pusch_config_pdu->dmrs_ports = table_7_3_1_1_2_20[dci->antenna_ports.val][1]; //TBC - //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_20[dci->antenna_ports.val][2]; //FIXME + //n_front_load_symb = table_7_3_1_1_2_20[dci->antenna_ports.val][2]; //FIXME } if (rank == 2){ @@ -502,7 +503,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf pusch_config_pdu->dmrs_ports = 0; //FIXME //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_21[dci->antenna_ports.val][1]; //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_21[dci->antenna_ports.val][2]; - //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME + //n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME } if (rank == 3){ @@ -511,7 +512,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_22[dci->antenna_ports.val][1]; //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_22[dci->antenna_ports.val][2]; //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_22[dci->antenna_ports.val][3]; - //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_22[dci->antenna_ports.val][4]; //FIXME + //n_front_load_symb = table_7_3_1_1_2_22[dci->antenna_ports.val][4]; //FIXME } if (rank == 4){ @@ -521,7 +522,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_23[dci->antenna_ports.val][2]; //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_23[dci->antenna_ports.val][3]; //pusch_config_pdu->dmrs_ports[3] = table_7_3_1_1_2_23[dci->antenna_ports.val][4]; - //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME + //n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME } } LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); @@ -565,7 +566,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos2; - pusch_maxLength_t dmrslength = pusch_len1; + int dmrslength = 1; if (rar_grant) { @@ -712,7 +713,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; ul_layers_config(mac, pusch_config_pdu, dci); - ul_ports_config(mac, pusch_config_pdu, dci); + ul_ports_config(mac, &dmrslength, pusch_config_pdu, dci); } else { @@ -805,22 +806,18 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->absolute_delta_PUSCH = 4; } - if (NR_DMRS_ulconfig != NULL) { + if (NR_DMRS_ulconfig != NULL) add_pos = (NR_DMRS_ulconfig->dmrs_AdditionalPosition == NULL) ? 2 : *NR_DMRS_ulconfig->dmrs_AdditionalPosition; - dmrslength = NR_DMRS_ulconfig->maxLength == NULL ? pusch_len1 : pusch_len2; - } /* DMRS */ l_prime_mask = get_l_prime(pusch_config_pdu->nr_of_symbols, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) - { - if (*dci_format != NR_UL_DCI_FORMAT_0_1) - { + if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + if (*dci_format != NR_UL_DCI_FORMAT_0_1) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; - } + } } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)) pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index eb727494d8..08208300fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -691,7 +691,6 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, "Non Codebook configuration non supported\n"); dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS } - AssertFatal((pusch_pdu->Tpmi==0), "unsupport Tpmi\n"); dci_pdu_rel15->precoding_information.val= 0; if (pusch_pdu->nrOfLayers == 2) { From c1d157dc429153fb2284b6fb13839cce81273dca Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 17 Jan 2022 19:28:17 +0100 Subject: [PATCH 025/226] fixing compilation issues --- cmake_targets/CMakeLists.txt | 3 +++ executables/nr-ue.c | 2 ++ openair1/SIMULATION/NR_PHY/dlschsim.c | 3 +++ openair1/SIMULATION/NR_PHY/nr_dummy_functions.c | 2 ++ openair1/SIMULATION/NR_PHY/pucchsim.c | 3 ++- openair1/SIMULATION/NR_PHY/ulschsim.c | 2 ++ 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index bf3bb2b017..0ff76d145f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -3171,6 +3171,7 @@ add_executable(nr_dlschsim ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${UTIL_SRC} ${T_SOURCE} ${SHLIB_LOADER_SOURCES} @@ -3203,6 +3204,7 @@ add_executable(nr_pucchsim ${OPENAIR_DIR}/common/utils/system.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${UTIL_SRC} ${T_SOURCE} ${SHLIB_LOADER_SOURCES} @@ -3259,6 +3261,7 @@ add_executable(nr_ulschsim ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${OPENAIR_DIR}/common/utils/nr/nr_common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${PHY_INTERFACE_DIR}/queue_t.c ${UTIL_SRC} ${T_SOURCE} diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d2553a03bf..747eb4bb45 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -19,6 +19,8 @@ * contact@openairinterface.org */ +#define _GNU_SOURCE +#include #include #include "executables/nr-uesoftmodem.h" #include "PHY/phy_extern_nr_ue.h" diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index ff07422c6b..5d34b75047 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -47,13 +47,16 @@ #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h" #include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c" + //#define DEBUG_NR_DLSCHSIM +THREAD_STRUCT thread_struct; PHY_VARS_gNB *gNB; PHY_VARS_NR_UE *UE; RAN_CONTEXT_t RC; UE_nr_rxtx_proc_t proc; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; double cpuf; //uint8_t nfapi_mode = 0; diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c index 7a47410129..69ae17c3ac 100644 --- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c +++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c @@ -20,6 +20,8 @@ nfapi_mode_t nfapi_mod; nfapi_mode_t nfapi_getmode(void) { return nfapi_mod; } +void nfapi_setmode(nfapi_mode_t nfapi_mode) {} + int dummy_nr_ue_dl_indication(nr_downlink_indication_t *dl_info) { return(0); } int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void nr_fill_dl_indication(nr_downlink_indication_t *dl_ind, diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 213924e5fd..9f268bb879 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -46,12 +46,13 @@ #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h" #include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c" - +THREAD_STRUCT thread_struct; PHY_VARS_gNB *gNB; PHY_VARS_NR_UE *UE; RAN_CONTEXT_t RC; openair0_config_t openair0_cfg[MAX_CARDS]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; double cpuf; //uint8_t nfapi_mode = 0; diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index fb8b4295ae..e51d790d24 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -49,10 +49,12 @@ //#define DEBUG_NR_ULSCHSIM +THREAD_STRUCT thread_struct; PHY_VARS_gNB *gNB; PHY_VARS_NR_UE *UE; RAN_CONTEXT_t RC; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {} From f05c1957512f299f454c3be6603a0f5378b95dfb Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 18 Jan 2022 09:15:05 +0100 Subject: [PATCH 026/226] bugfix for nl index --- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 84ad8aa8af..7fb1a15fac 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -103,7 +103,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); uint32_t available_bits; - uint8_t cwd_index, l; + uint8_t cwd_index; uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; int8_t Wf[2], Wt[2]; int l_prime[2], delta; @@ -282,7 +282,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); - for (l = start_symbol; l < start_symbol + number_of_symbols; l++) { + for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { if((ul_dmrs_symb_pos >> l) & 0x01) /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ @@ -333,7 +333,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH RE mapping///////////////////////// /////////// - for (int l=0; l < Nl; l++) { + for (int nl=0; nl < Nl; nl++) { uint8_t k_prime = 0; uint16_t m = 0; @@ -341,13 +341,13 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); #endif - int dmrs_port = get_dmrs_port(l,pusch_pdu->dmrs_ports); + int dmrs_port = get_dmrs_port(nl,pusch_pdu->dmrs_ports); // DMRS params for this dmrs port get_Wt(Wt, dmrs_port, dmrs_type); get_Wf(Wf, dmrs_port, dmrs_type); delta = get_delta(dmrs_port, dmrs_type); - for (l=start_symbol; ltransformPrecoder == transformPrecoder_enabled) { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; } else { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; } #ifdef DEBUG_PUSCH_MAPPING printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", - l, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1], - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1]); + l, dmrs_idx, l, k, k_prime, n, ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1]); #endif dmrs_idx++; @@ -424,32 +424,32 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, n+=(k_prime)?0:1; } else if (is_ptrs == 1) { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; ptrs_idx++; } else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[l])[m<<1]; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[l])[(m<<1) + 1]; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[nl])[m<<1]; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[nl])[(m<<1) + 1]; } else { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; } #ifdef DEBUG_PUSCH_MAPPING printf("DATA: layer %d\t m %d\t l %d \t k %d \t txdataF: %d %d\n", - l, m, l, k, ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1], - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1]); + nl, m, l, k, ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1], + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1]); #endif m++; } else { - ((int16_t*)tx_precoding[l])[(sample_offsetF)<<1] = 0; - ((int16_t*)tx_precoding[l])[((sample_offsetF)<<1) + 1] = 0; + ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = 0; + ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = 0; } if (++k >= frame_parms->ofdm_symbol_size) { @@ -457,7 +457,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, } } //for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) }//for (l=start_symbol; l Date: Tue, 18 Jan 2022 11:53:57 +0100 Subject: [PATCH 027/226] Shutdown nr-softmodem cleanly --- common/utils/ocp_itti/intertask_interface.cpp | 1 + executables/nr-softmodem.c | 1 - openair1/PHY/INIT/nr_init_ru.c | 12 +++++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 44fae9f788..111a423dcb 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -450,6 +450,7 @@ extern "C" { void itti_wait_tasks_end(void) { shutting_down = false; signal(SIGTERM, catch_sigterm); + signal(SIGINT, catch_sigterm); while (! shutting_down) { sleep(24 * 3600); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 2b8335167a..9dbc94637c 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -876,7 +876,6 @@ int main( int argc, char **argv ) { nr_phy_free_RU(RC.ru[inst]); } - free_lte_top(); pthread_cond_destroy(&sync_cond); pthread_mutex_destroy(&sync_mutex); pthread_cond_destroy(&nfapi_sync_cond); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 4024ed1617..73666b48ac 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -193,7 +193,7 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.rxdata_7_5kHz); // free beamforming input buffers (TX) - for (i = 0; i < 15; i++) free_and_zero(ru->common.txdataF[i]); + for (i = 0; i < ru->nb_tx; i++) free_and_zero(ru->common.txdataF[i]); free_and_zero(ru->common.txdataF); // free IFFT input buffers (TX) @@ -209,10 +209,12 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->prach_rxsigF[j][i]); } } - for (i = 0; i < ru->num_gNB; i++) { - for (p = 0; p < 15; p++) { - for (j=0; jnb_tx; j++) free_and_zero(ru->beam_weights[i][p][j]); - free_and_zero(ru->beam_weights[i][p]); + if (ru->do_precoding == 1) { + for (i = 0; i < ru->num_gNB; i++) { + for (p = 0; p < ru->nb_log_antennas; p++) { + for (j=0; jnb_tx; j++) free_and_zero(ru->beam_weights[i][p][j]); + free_and_zero(ru->beam_weights[i][p]); + } } } } From a2244ab32ddd25b97bdaadded7ad2bca4874ad1b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 18 Jan 2022 14:21:58 +0100 Subject: [PATCH 028/226] Stop RU threads at end of nr-softmodem --- executables/nr-softmodem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 9dbc94637c..60efba8464 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -873,6 +873,7 @@ int main( int argc, char **argv ) { } for (int inst = 0; inst < NB_RU; inst++) { + kill_NR_RU_proc(inst); nr_phy_free_RU(RC.ru[inst]); } From 18fd38fa082d878bcee2b2aa6afee021583c5cda Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 18 Jan 2022 14:23:54 +0100 Subject: [PATCH 029/226] Don't call trx_end_func() at nr-softmodem, is done in ru_thread() --- executables/nr-softmodem.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 60efba8464..e01c3078c5 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -886,9 +886,6 @@ int main( int argc, char **argv ) { // *** Handle per CC_id openair0 for(ru_id=0; ru_idrfdevice.trx_end_func) - RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); - if (RC.ru[ru_id]->ifdevice.trx_end_func) RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); } From 3377f91b627e3467d5fbec6c6e4c3daad9375650 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 19 Jan 2022 11:48:51 +0100 Subject: [PATCH 030/226] fix free pusch_vars->rho --- openair1/PHY/INIT/nr_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index d3f1b02826..4b3a896893 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -363,6 +363,7 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) for (int i = 0; i < fp->nb_antennas_rx; i++) { free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext[i]); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext2[i]); + free_and_zero(pusch_vars[ULSCH_id]->rho[i]); } for (int i = 0; i < 4*fp->nb_antennas_rx; i++) { free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates[i]); @@ -376,7 +377,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb[i]); - free_and_zero(pusch_vars[ULSCH_id]->rho[i]); } free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext2); From 4bdc6ac59f1838da60846fc42adf030cf2de99d8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 19 Jan 2022 18:11:43 +0100 Subject: [PATCH 031/226] minor changes --- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 18 ++++-------- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 29 +++++++------------ openair1/SIMULATION/NR_PHY/ulsim.c | 1 - 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 5286fe8780..3f6540a94a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -298,16 +298,7 @@ void nr_processULSegment(void* arg) { stop_meas(&phy_vars_gNB->ulsch_deinterleaving_stats); - /*LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", - harq_pid,r, G, - Kr*3, - ulsch_harq->TBS, - Qm, - nb_rb, - n_layers, - pusch_pdu->pusch_data.rv_index, - ulsch_harq->round);*/ - ////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// @@ -387,13 +378,13 @@ void nr_processULSegment(void* arg) { if (check_crc((uint8_t*)llrProcBuf,length_dec,ulsch_harq->F,crc_type)) { #ifdef PRINT_CRC_CHECK - LOG_I(PHY, "Segment %d CRC OK, iterations %d/%d\n",r,no_iteration_ldpc,max_ldpc_iterations); + LOG_I(PHY,"Segment %d CRC OK, iterations %d/%d\n",r,no_iteration_ldpc,max_ldpc_iterations); #endif rdata->decodeIterations = no_iteration_ldpc; if (rdata->decodeIterations > p_decoderParms->numMaxIter) rdata->decodeIterations--; } else { #ifdef PRINT_CRC_CHECK - LOG_I(PHY, "CRC NOK\n"); + LOG_I(PHY,"CRC NOK\n"); #endif rdata->decodeIterations = max_ldpc_iterations + 1; } @@ -480,7 +471,8 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, A = (harq_process->TBS)<<3; - LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, n_layers %d, Coderate %d\n",harq_pid,A,G, mcs, n_layers, nb_rb, Qm, n_layers, R); + LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, Coderate %d RV %d round %d\n", + harq_pid, A, G, mcs, n_layers, nb_rb, Qm, R, pusch_pdu->pusch_data.rv_index, harq_process->round); if (R<1024) Coderate = (float) R /(float) 1024; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index dad8d70465..26a7c953c9 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -347,14 +347,12 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, if (is_dmrs_symbol == 0) { // //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); - if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) - { + if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { memcpy1((void*)rxF_ext, (void*)&rxF[start_re*2], nb_re_pusch*sizeof(int32_t)); } - else - { + else { int neg_length = frame_parms->ofdm_symbol_size-start_re; int pos_length = nb_re_pusch-neg_length; memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); @@ -373,8 +371,7 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); } } - else - { + else { #ifdef SUPPORT_PMI_MATRIC for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) #else @@ -390,26 +387,22 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, ul_ch0_ext_index = 0; ul_ch0_index = 0; - for (re = 0; re < nb_re_pusch; re++) - { + for (re = 0; re < nb_re_pusch; re++) { uint16_t k= start_re+re; is_data_re = allowed_xlsch_re_in_dmrs_symbol(k, start_re, frame_parms->ofdm_symbol_size, pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type); - if (++k >= frame_parms->ofdm_symbol_size) - { + if (++k >= frame_parms->ofdm_symbol_size) { k -= frame_parms->ofdm_symbol_size; } #ifdef DEBUG_RB_EXT - printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol); + printf("re = %d, is_dmrs_symbol = %d, symbol = %d\n", re, is_dmrs_symbol, symbol); #endif /* save only data and respective channel estimates */ - if (is_data_re == 1) - { - if (aatx == aarx) - { + if (is_data_re == 1) { + if (aatx == aarx) { rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); rxF_ext_index +=2; @@ -1206,8 +1199,7 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, if (n_rx > 1) { #if defined(__x86_64__) || defined(__i386__) - for (int aatx=0; aatxnb_antennas_rx][(symbol*(nb_re + off))]; @@ -2002,8 +1994,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] = 0; gNB->pusch_vars[ulsch_id]->ulsch_noise_power[aarx] = 0; } - for (aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) - { + for (aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) { gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] += signal_energy_nodc( &gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aatx*gNB->frame_parms.nb_antennas_rx+aarx][symbol * frame_parms->ofdm_symbol_size], rel15_ul->rb_size * 12); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 32cb2d6d48..8bf43ef0b1 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -243,7 +243,6 @@ nrUE_params_t *get_nrUE_params(void) { // needed for some functions uint16_t n_rnti = 0x1234; openair0_config_t openair0_cfg[MAX_CARDS]; -//const uint8_t nr_rv_round_map[4] = {0, 2, 1, 3}; channel_desc_t *UE2gNB[NUMBER_OF_UE_MAX][NUMBER_OF_gNB_MAX]; From cd5e07b67cf933df873e2ea6775300dcb3494d75 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 24 Jan 2022 15:06:02 +0100 Subject: [PATCH 032/226] minor change after merge with develop --- executables/nr-ru.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 6891a360f3..c7375601a6 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1312,6 +1312,7 @@ void *ru_thread( void *param ) { else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + LOG_I(PHY,"RU %d RF started\n",ru->idx); // start trx write thread if(usrp_tx_thread == 1) { if (ru->start_write_thread) { From 86560439e73d22ca0e3341fda5c5694968104a84 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 1 Feb 2022 21:55:49 +0100 Subject: [PATCH 033/226] nr-softmodem fixed after merge` --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 ++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 3 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 91187a88f8..a4ef3e425f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -580,14 +580,14 @@ bool allocate_dl_retransmission(module_id_t module_id, } else { /* the retransmission will use a different time domain allocation, check * that we have enough resources */ + NR_pdsch_semi_static_t temp_ps = *ps; + nr_set_pdsch_semi_static(scc, cg, sched_ctrl->active_bwp, bwpd,tda, ps->nrOfLayers, sched_ctrl, &temp_ps); while (rbStart < bwpSize && !(rballoc_mask[rbStart]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) rbStart++; while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) rbSize++; - NR_pdsch_semi_static_t temp_ps = *ps; - nr_set_pdsch_semi_static(scc, cg, sched_ctrl->active_bwp, bwpd,tda, ps->nrOfLayers, sched_ctrl, &temp_ps); uint32_t new_tbs; uint16_t new_rbSize; bool success = nr_find_nb_rb(retInfo->Qm, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 633ff0e54c..40890cf258 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -284,7 +284,7 @@ void nr_preprocessor_phytest(module_id_t module_id, ps->nrOfLayers = target_dl_Nl; if (ps->time_domain_allocation != tda) nr_set_pdsch_semi_static( - scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, NULL, tda, f, ps); + scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, NULL, tda, target_dl_Nl, sched_ctrl,ps); /* find largest unallocated chunk */ const int bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); @@ -389,7 +389,6 @@ void nr_preprocessor_phytest(module_id_t module_id, sched_pdsch->pucch_allocation = alloc; sched_pdsch->rbStart = rbStart; sched_pdsch->rbSize = rbSize; - const int tda = sched_ctrl->active_bwp ? RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] : 1; if (ps->time_domain_allocation != tda || ps->nrOfLayers != target_dl_Nl) nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, NULL, tda, target_dl_Nl, sched_ctrl, ps); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 21e8419884..24a01fe8ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2137,7 +2137,6 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG UE_info->CellGroup[UE_id] = CellGroup; add_nr_list(&UE_info->list, UE_id); memset(&UE_info->mac_stats[UE_id], 0, sizeof(NR_mac_stats_t)); - set_Y(UE_info->Y[UE_id], rntiP); if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated && From 2b96909960979eff578ba3756a63d612126073e2 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 11 Feb 2022 08:11:45 +0100 Subject: [PATCH 034/226] update to ori.h (with NR extensions) --- targets/ARCH/AW2SORI/ori.h | 113 ++++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 9 deletions(-) diff --git a/targets/ARCH/AW2SORI/ori.h b/targets/ARCH/AW2SORI/ori.h index d4a4f2cbbf..3650d15ec6 100644 --- a/targets/ARCH/AW2SORI/ori.h +++ b/targets/ARCH/AW2SORI/ori.h @@ -2,8 +2,8 @@ * @file ori.h * @brief Open Radio Interface (ORI) C library header file. * @author AW2S (http://www.aw2s.com) -* @version 1.6 -* @date July 29, 2019 +* @version 1.8 +* @date January 18, 2022 * * This file is the AW2S REC ORI C library header, and contains all necessary * functions prototypes, enumerations, data structures and type definitions @@ -14,7 +14,7 @@ #define ORI_H_ #define ORILIB_VERSION_MAJOR 1 -#define ORILIB_VERSION_MINOR 6 +#define ORILIB_VERSION_MINOR 8 #include @@ -144,10 +144,14 @@ typedef enum ORI_ObjectType_TxEUtraFDD, /**< */ ORI_ObjectType_TxEUtraTDD, /**< */ ORI_ObjectType_TxGSM, /**< */ + ORI_ObjectType_TxNRFDD, /**< */ + ORI_ObjectType_TxNRTDD, /**< */ ORI_ObjectType_RxUtra, /**< */ ORI_ObjectType_RxEUtraFDD, /**< */ ORI_ObjectType_RxEUtraTDD, /**< */ ORI_ObjectType_RxGSM, /**< */ + ORI_ObjectType_RxNRFDD, /**< */ + ORI_ObjectType_RxNRTDD, /**< */ ORI_ObjectType_ORILink, /**< */ ORI_ObjectType_ExternalEventPort, /**< */ ORI_ObjectType_AISGPort, /**< */ @@ -223,6 +227,7 @@ typedef enum ORI_ObjectParam_SigPath_AWS_enableCompBitChange, /**< */ ORI_ObjectParam_SigPath_AWS_measuredPwr, /**< */ ORI_ObjectParam_SigPath_AWS_axcIncr, /**< */ + ORI_ObjectParam_SigPath_AWS_arfcn, /**< */ ORI_ObjectParam_TxSigPath_t2a, /**< */ ORI_ObjectParam_TxSigPath_maxTxPwr, /**< */ ORI_ObjectParam_TxSigPath_dlCalRE, /**< */ @@ -252,12 +257,12 @@ typedef enum ORI_ObjectParam_ORILink_AWS_localMAC, /**< */ ORI_ObjectParam_ORILink_AWS_remoteMAC, /**< */ ORI_ObjectParam_ORILink_AWS_t14, /**< */ + ORI_ObjectParam_ORILink_AWS_sfpTxPow, /**< */ + ORI_ObjectParam_ORILink_AWS_sfpRxPow, /**< */ ORI_ObjectParam_ORILink_AWS_remoteIP, /**< */ ORI_ObjectParam_ORILink_AWS_localIP, /**< */ ORI_ObjectParam_ORILink_AWS_remoteUdpPort, /**< */ ORI_ObjectParam_ORILink_AWS_localUdpPort, /**< */ - ORI_ObjectParam_ORILink_AWS_sfpTxPow, /**< */ - ORI_ObjectParam_ORILink_AWS_sfpRxPow, /**< */ ORI_ObjectParam_AISGPort_busPowerEnable, /**< */ ORI_ObjectParam_AISGALD_deviceType, /**< */ ORI_ObjectParam_AISGALD_UID, /**< */ @@ -1146,6 +1151,50 @@ typedef struct ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ } ORI_ObjectParams_TxSigPathGSM_s; +/** + * @struct ORI_ObjectParams_TxSigPathNRFDD_s + * @brief Structure containing the parameters of a TxSigPath NRFDD object. + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t dlCalREMax; /**< RO. Max possible buffer in RE for DL timing calibration in Tc/16.*/ + uint32_t t2a; /**< RO. RE time delay. */ + uint16_t dlCalRE; /**< RW-Locked. Time delay to enable DL timing calibration in Tc/16. */ + int16_t maxTxPwr; /**< RW. Max tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_TxSigPathNRFDD_s; + +/** + * @struct ORI_ObjectParams_TxSigPathNRTDD_s + * @brief Structure containing the parameters of a TxSigPath NRTDD object. + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t dlCalREMax; /**< RO. Max possible buffer in RE for DL timing calibration in Tc/16.*/ + uint32_t t2a; /**< RO. RE time delay. */ + uint16_t dlCalRE; /**< RW-Locked. Time delay to enable DL timing calibration in Tc/16. */ + int16_t maxTxPwr; /**< RW. Max tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_TxSigPathNRTDD_s; + /** * @struct ORI_ObjectParams_RxSigPathUtra_s * @brief Structure containing the parameters of a RxSigPath UTRAFDD object. @@ -1239,6 +1288,48 @@ typedef struct uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ } ORI_ObjectParams_RxSigPathGSM_s; +/** + * @struct ORI_ObjectParams_RxSigPathNRFDD_s + * @brief Structure containing the parameters of a RxSigPath NRFDD object. + * + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t ulCalREMax; /**< RO. Max possible buffer in RE for UL timing calibration in Tc/2.*/ + uint32_t ta3; /**< RO. RE time delay. */ + uint16_t ulCalRE; /**< RW-Locked. Time delay to enable UL timing calibration in Tc/2. */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Rx power for this path, unit is dBm/10 (e.g. -650 for -65 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_RxSigPathNRFDD_s; + +/** + * @struct ORI_ObjectParams_RxSigPathNRTDD_s + * @brief Structure containing the parameters of a RxSigPath NRTDD object. + * + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t ulCalREMax; /**< RO. Max possible buffer in RE for UL timing calibration in Tc/2.*/ + uint32_t ta3; /**< RO. RE time delay. */ + uint16_t ulCalRE; /**< RW-Locked. Time delay to enable UL timing calibration in Tc/2. */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Rx power for this path, unit is dBm/10 (e.g. -650 for -65 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_RxSigPathNRTDD_s; + /** * @struct ORI_ObjectParams_ORILink_s * @brief Structure containing the parameters of an ORI Link object. @@ -1258,12 +1349,12 @@ typedef struct uint8_t AWS_localMAC[6]; /**< R0. AW2S Vendor specific: Local MAC address of the ORI link. */ uint8_t AWS_remoteMAC[6]; /**< RW. AW2S Vendor specific: Remote MAC address of the ORI link. */ uint32_t AWS_t14; /**< RO. AW2S Vendor specific: CPRI time delay component. */ - uint8_t AWS_remoteIP[4]; /**< RW. AW2S Vendor specific: REC IP for ECPRI Ethernet frame */ - uint8_t AWS_localIP[4]; /**< R0. AW2S Vendor specific: RE IP for ECPRI Ethernet frame */ - uint16_t AWS_remoteUdpPort; /**< RW. AW2S Vendor specific: REC Udp Port for ECPRI Ethernet frame */ - uint16_t AWS_localUdpPort; /**< R0. AW2S Vendor specific: RE Udp Port for ECPRI Ethernet frame */ uint32_t AWS_sfpTxPow; /**< RO. AW2S Vendor specific: SFP Tx power. */ uint32_t AWS_sfpRxPow; /**< RO. AW2S Vendor specific: SFP Rx power. */ + uint8_t AWS_remoteIP[4]; /**< RW. AW2S Vendor specific: IP of REC for ECPRI Ethernet frame */ + uint8_t AWS_localIP[4]; /**< RW. AW2S Vendor specific: IP of RE for ECPRI Ethernet frame */ + uint16_t AWS_remoteUdpPort; /**< RW. AW2S Vendor specific: UDP port of REC for ECPRI Ethernet frame */ + uint16_t AWS_localUdpPort; /**< RO. AW2S Vendor specific: UDP port of RE for ECPRI Ethernet frame */ } ORI_ObjectParams_ORILink_s; /** @@ -1393,10 +1484,14 @@ typedef union ORI_ObjectParams_TxSigPathEUtraFDD_s TxEUtraFDD; /**< Parameters for ::ORI_ObjectType_TxEUtraFDD. */ ORI_ObjectParams_TxSigPathEUtraTDD_s TxEUtraTDD; /**< Parameters for ::ORI_ObjectType_TxEUtraTDD. */ ORI_ObjectParams_TxSigPathGSM_s TxGSM; /**< Parameters for ::ORI_ObjectType_TxGSM. */ + ORI_ObjectParams_TxSigPathNRFDD_s TxNRFDD; /**< Parameters for ::ORI_ObjectType_TxNRFDD. */ + ORI_ObjectParams_TxSigPathNRTDD_s TxNRTDD; /**< Parameters for ::ORI_ObjectType_TxNRTDD. */ ORI_ObjectParams_RxSigPathUtra_s RxUtra; /**< Parameters for ::ORI_ObjectType_RxUtra. */ ORI_ObjectParams_RxSigPathEUtraFDD_s RxEUtraFDD; /**< Parameters for ::ORI_ObjectType_RxEUtraFDD. */ ORI_ObjectParams_RxSigPathEUtraTDD_s RxEUtraTDD; /**< Parameters for ::ORI_ObjectType_RxEUtraTDD. */ ORI_ObjectParams_RxSigPathGSM_s RxGSM; /**< Parameters for ::ORI_ObjectType_RxGSM. */ + ORI_ObjectParams_RxSigPathNRFDD_s RxNRFDD; /**< Parameters for ::ORI_ObjectType_RxNRFDD. */ + ORI_ObjectParams_RxSigPathNRTDD_s RxNRTDD; /**< Parameters for ::ORI_ObjectType_RxNRTDD. */ ORI_ObjectParams_ORILink_s ORILink; /**< Parameters for ::ORI_ObjectType_ORILink. */ ORI_ObjectParams_ExternalEventPort_s ExternalEventPort; /**< Parameters for ::ORI_ObjectType_ExternalEventPort. */ ORI_ObjectParams_AISGPort_s AISGPort; /**< Parameters for ::ORI_ObjectType_AISGPort. */ From 74fd3f029adf496422d6cefe5c590ad2209176d1 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 13 Feb 2022 09:44:15 +0100 Subject: [PATCH 035/226] changes for AW2S NR support in ORI library --- executables/nr-ru.c | 11 +- openair2/ENB_APP/enb_paramdef.h | 6 + openair2/GNB_APP/gnb_config.c | 12 +- targets/ARCH/AW2SORI/oaiori.c | 351 +++++++++++++++++++++++++------ targets/ARCH/COMMON/common_lib.h | 6 + 5 files changed, 305 insertions(+), 81 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index c3788ef480..e4fc3bc27c 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -2084,9 +2084,7 @@ static void NRRCconfig_RU(void) { RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); - RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); - for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; } //strcmp(local_rf, "yes") == 0 else { printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); @@ -2106,8 +2104,6 @@ static void NRRCconfig_RU(void) { RC.ru[j]->if_south = REMOTE_IF5; RC.ru[j]->function = NGFI_RAU_IF5; RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { RC.ru[j]->if_south = REMOTE_IF5; RC.ru[j]->function = NGFI_RAU_IF5; @@ -2130,7 +2126,12 @@ static void NRRCconfig_RU(void) { RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr); RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr); RC.ru[j]->do_precoding = *(RUParamList.paramarray[j][RU_DO_PRECODING].iptr); - + RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; + for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; + RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr); + RC.ru[j]->openair0_cfg.nr_band = RC.ru[j]->band[0]; + RC.ru[j]->openair0_cfg.nr_scs_for_raster = *(RUParamList.paramarray[j][RU_NR_SCS_FOR_RASTER].iptr); + printf("[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n",j,RC.ru[j]->openair0_cfg.nr_flag,RC.ru[j]->openair0_cfg.nr_band,RC.ru[j]->openair0_cfg.nr_scs_for_raster); if (config_isparamset(RUParamList.paramarray[j], RU_BF_WEIGHTS_LIST_IDX)) { RC.ru[j]->nb_bfw = RUParamList.paramarray[j][RU_BF_WEIGHTS_LIST_IDX].numelt; diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 22af2a6de0..2757e408d9 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -99,6 +99,8 @@ typedef enum { #define CONFIG_STRING_RU_IF_FREQUENCY "if_freq" #define CONFIG_STRING_RU_IF_FREQ_OFFSET "if_offset" #define CONFIG_STRING_RU_DO_PRECODING "do_precoding" +#define CONFIG_STRING_RU_NR_FLAG "nr_flag" +#define CONFIG_STRING_RU_NR_SCS_FOR_RASTER "nr_scs_for_raster" #define RU_LOCAL_IF_NAME_IDX 0 #define RU_LOCAL_ADDRESS_IDX 1 @@ -129,6 +131,8 @@ typedef enum { #define RU_IF_FREQUENCY 26 #define RU_IF_FREQ_OFFSET 27 #define RU_DO_PRECODING 28 +#define RU_NR_FLAG 29 +#define RU_NR_SCS_FOR_RASTER 30 /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* RU configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -163,6 +167,8 @@ typedef enum { {CONFIG_STRING_RU_IF_FREQUENCY, NULL, 0, u64ptr:NULL, defuintval:0, TYPE_UINT64, 0}, \ {CONFIG_STRING_RU_IF_FREQ_OFFSET, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_DO_PRECODING, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_NR_FLAG, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ } /*---------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 9a0c972c09..deeb1b505d 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -451,7 +451,7 @@ void fix_scd(NR_ServingCellConfig_t *scd) { for (int i = scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.count-1; i >= 0; i--) { if ((*scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1) || (*scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) { - LOG_I(RRC, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); + LOG_I(NR_RRC, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); free(scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS); scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS = NULL; break; @@ -1149,16 +1149,16 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { (NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d", NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l]); } - printf("SSB SCO %d\n",*GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr); + LOG_I(GNB_APP,"SSB SCO %d\n",*GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).ssb_SubcarrierOffset = *GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr; - printf("pdsch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr); + LOG_I(GNB_APP,"pdsch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr; - printf("pusch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr); + LOG_I(GNB_APP,"pusch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).pusch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr; - printf("minTXRXTIME %d\n",*GNBParamList.paramarray[i][GNB_MINRXTXTIME_IDX].iptr); + LOG_I(GNB_APP,"minTXRXTIME %d\n",*GNBParamList.paramarray[i][GNB_MINRXTXTIME_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).minRXTXTIME = *GNBParamList.paramarray[i][GNB_MINRXTXTIME_IDX].iptr; NRRRC_CONFIGURATION_REQ (msg_p).sib1_tda = *GNBParamList.paramarray[i][GNB_SIB1_TDA_IDX].iptr; - printf("Do CSI-RS %d\n",*GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr); + LOG_I(GNB_APP,"Do CSI-RS %d\n",*GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).do_CSIRS = *GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr; NRRRC_CONFIGURATION_REQ (msg_p).scc = scc; NRRRC_CONFIGURATION_REQ (msg_p).scd = scd; diff --git a/targets/ARCH/AW2SORI/oaiori.c b/targets/ARCH/AW2SORI/oaiori.c index ea39d9c90d..4b0c83ab4c 100644 --- a/targets/ARCH/AW2SORI/oaiori.c +++ b/targets/ARCH/AW2SORI/oaiori.c @@ -228,14 +228,38 @@ int aw2s_startstreaming(openair0_device *device) { ORI_Result_e RE_result; openair0_config_t *openair0_cfg = device->openair0_cfg; + ORI_Object_s *tx0,*tx1,*tx2,*tx3,*rx0,*rx1,*rx2,*rx3; + if (openair0_cfg->nr_flag == 0 ) { + tx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ? ORI_ObjectType_TxEUtraFDD :ORI_ObjectType_TxEUtraTDD, 0, NULL); + tx1= (openair0_cfg->tx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxEUtraTDD, 1, NULL) : NULL; + tx2= (openair0_cfg->tx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxEUtraTDD, 2, NULL) : NULL; + tx3= (openair0_cfg->tx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxEUtraTDD, 3, NULL) : NULL; + rx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 0, NULL); + rx1= (openair0_cfg->rx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 1, NULL) : NULL; + rx2= (openair0_cfg->rx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 2, NULL) : NULL; + rx3= (openair0_cfg->rx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 3, NULL) : NULL; + } else { + tx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ? ORI_ObjectType_TxNRFDD :ORI_ObjectType_TxNRTDD, 0, NULL); + tx1= (openair0_cfg->tx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 1, NULL) : NULL; + tx2= (openair0_cfg->tx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 2, NULL) : NULL; + tx3= (openair0_cfg->tx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 3, NULL) : NULL; + rx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 0, NULL); + rx1= (openair0_cfg->rx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 1, NULL) : NULL; + rx2= (openair0_cfg->rx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 2, NULL) : NULL; + rx3= (openair0_cfg->rx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 3, NULL) : NULL; - ORI_Object_s *tx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ? ORI_ObjectType_TxEUtraFDD :ORI_ObjectType_TxEUtraTDD, 0, NULL); - ORI_Object_s *tx1= (openair0_cfg->tx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxEUtraTDD, 1, NULL) : NULL; - ORI_Object_s *rx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 0, NULL); - ORI_Object_s *rx1= (openair0_cfg->rx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 1, NULL) : NULL; + } ORI_Object_s *link= ORI_FindObject(ori, ORI_ObjectType_ORILink, 0, NULL); - if (tx0 == NULL || (tx1 == NULL && openair0_cfg->tx_num_channels > 1) || rx0 == NULL || (rx1 == NULL && openair0_cfg->rx_num_channels > 1) || link == NULL) return (-1); + if (tx0 == NULL || + (tx1 == NULL && openair0_cfg->tx_num_channels > 1) || + (tx2 == NULL && openair0_cfg->tx_num_channels > 2) || + (tx3 == NULL && openair0_cfg->tx_num_channels > 3) || + rx0 == NULL || + (rx1 == NULL && openair0_cfg->rx_num_channels > 1) || + (rx2 == NULL && openair0_cfg->rx_num_channels > 2) || + (rx3 == NULL && openair0_cfg->rx_num_channels > 3) || + link == NULL) return (-1); /******************************************************************* * UNLOCK Link @@ -284,6 +308,40 @@ int aw2s_startstreaming(openair0_device *device) { } printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); } + /******************************************************************* + * UNLOCK TX2 + *******************************************************************/ + + if (tx2) { + printf("\n\n\n========================================================\n"); + + /* Put Tx1 into service */ + result = ORI_ObjectStateModification(ori, tx2, ORI_AST_Unlocked, &RE_result); + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); + } + /******************************************************************* + * UNLOCK TX3 + *******************************************************************/ + + if (tx3) { + printf("\n\n\n========================================================\n"); + + /* Put Tx3 into service */ + result = ORI_ObjectStateModification(ori, tx1, ORI_AST_Unlocked, &RE_result); + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); + } /******************************************************************* * UNLOCK RX0 *******************************************************************/ @@ -320,6 +378,38 @@ int aw2s_startstreaming(openair0_device *device) { printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); } + /******************************************************************* + * UNLOCK RX2 + *******************************************************************/ + if (rx2) { + printf("\n\n\n========================================================\n"); + + /* Put Rx1 into service */ + result = ORI_ObjectStateModification(ori, rx2, ORI_AST_Unlocked, &RE_result); + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); + } + /******************************************************************* + * UNLOCK RX3 + *******************************************************************/ + if (rx3) { + printf("\n\n\n========================================================\n"); + + /* Put Rx1 into service */ + result = ORI_ObjectStateModification(ori, rx3, ORI_AST_Unlocked, &RE_result); + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result)); + } /* while (rx0->fst != ORI_FST_Operational || (openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) || @@ -331,6 +421,9 @@ int aw2s_startstreaming(openair0_device *device) { uint64_t TS; char temp_rx[1024] __attribute__((aligned(32))); int aid,r0=0,r1=(openair0_cfg->rx_num_channels > 1) ? 0 : 1; + int r2=(openair0_cfg->rx_num_channels > 2) ? 0 : 1; + int r3=(openair0_cfg->rx_num_channels > 3) ? 0 : 1; + int i; int Npackets=1024000; for (i=0;iduplex_mode == duplex_mode_FDD ? ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxEUtraTDD}; + ORI_ObjectTypeRef_s txTypeRef = { NULL, openair0_cfg->duplex_mode == duplex_mode_FDD ? + (openair0_cfg->nr_flag == 0 ? ORI_ObjectType_TxEUtraFDD : ORI_ObjectType_TxNRFDD): + (openair0_cfg->nr_flag == 0 ? ORI_ObjectType_TxEUtraTDD : ORI_ObjectType_TxNRTDD)}; ORI_ObjectParams_u txParams; ORI_ObjectParam_e txParamList[9]; ORI_Result_e txParamResult[9]; int num_txparams; - if (openair0_cfg->duplex_mode == duplex_mode_FDD) { - txParamList[0] = ORI_ObjectParam_SigPath_antPort; - txParamList[1] = ORI_ObjectParam_SigPath_axcW; - txParamList[2] = ORI_ObjectParam_SigPath_axcB; - txParamList[3] = ORI_ObjectParam_SigPath_chanBW; - txParamList[4] = ORI_ObjectParam_SigPath_earfcn; - txParamList[5] = ORI_ObjectParam_TxSigPath_maxTxPwr; - num_txparams = 6; - } - else { - txParamList[0] = ORI_ObjectParam_SigPath_antPort; - txParamList[1] = ORI_ObjectParam_SigPath_axcW; - txParamList[2] = ORI_ObjectParam_SigPath_axcB; - txParamList[3] = ORI_ObjectParam_SigPath_chanBW; - txParamList[4] = ORI_ObjectParam_SigPath_earfcn; - txParamList[5] = ORI_ObjectParam_TxSigPath_maxTxPwr; - txParamList[6] = ORI_ObjectParam_SigPath_tddULDLConfig; - txParamList[7] = ORI_ObjectParam_SigPath_tddSpecialSFConfig; - txParamList[8] = ORI_ObjectParam_TxSigPath_tddCPLengthDL; - num_txparams = 9; - } + txParamList[0] = ORI_ObjectParam_SigPath_antPort; + txParamList[1] = ORI_ObjectParam_SigPath_axcW; + txParamList[2] = ORI_ObjectParam_SigPath_axcB; + txParamList[3] = ORI_ObjectParam_SigPath_chanBW; + txParamList[4] = (openair0_cfg->nr_flag ==0) ? ORI_ObjectParam_SigPath_earfcn : ORI_ObjectParam_SigPath_AWS_arfcn; + txParamList[5] = ORI_ObjectParam_TxSigPath_maxTxPwr; + num_txparams = 6; /* Create tx0 */ ORI_Object_s * tx0; printf("AW2S: duplex_mode %d, tx_bw %f, rx_bw %f\n",openair0_cfg->duplex_mode,openair0_cfg->tx_bw,openair0_cfg->rx_bw); - if (openair0_cfg->duplex_mode == duplex_mode_FDD) { + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) { txParams.TxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); txParams.TxEUtraFDD.axcW = 1; txParams.TxEUtraFDD.axcB = 0; txParams.TxEUtraFDD.chanBW = openair0_cfg->tx_bw/100e3; - txParams.TxEUtraFDD.earfcn = 3350; - txParams.TxEUtraFDD.maxTxPwr = -100; + txParams.TxEUtraTDD.earfcn = to_earfcn_DL_aw2s(-1,(long long int)openair0_cfg->tx_freq[0],txParams.TxEUtraTDD.chanBW); + txParams.TxEUtraFDD.maxTxPwr = 430-((int)openair0_cfg->tx_gain[0]*10); } - else if (openair0_cfg->duplex_mode == duplex_mode_TDD) { + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) { + txParams.TxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); + txParams.TxNRFDD.axcW = 1; + txParams.TxNRFDD.axcB = 0; + txParams.TxNRFDD.chanBW = openair0_cfg->tx_bw/100e3; + + txParams.TxNRFDD.AWS_arfcn = to_nrarfcn(openair0_cfg->nr_band,(long long int)openair0_cfg->tx_freq[0],openair0_cfg->nr_scs_for_raster,(uint32_t)openair0_cfg->tx_bw); + txParams.TxNRFDD.maxTxPwr = 430-((int)openair0_cfg->tx_gain[0]*10); + } + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) { txParams.TxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); txParams.TxEUtraTDD.axcW = 1; txParams.TxEUtraTDD.axcB = 0; txParams.TxEUtraTDD.chanBW = openair0_cfg->tx_bw/100e3; txParams.TxEUtraTDD.earfcn = to_earfcn_DL_aw2s(-1,(long long int)openair0_cfg->tx_freq[0],txParams.TxEUtraTDD.chanBW); txParams.TxEUtraTDD.maxTxPwr = 430-((int)openair0_cfg->tx_gain[0]*10); - txParams.TxEUtraTDD.tddULDLConfig = 1; - txParams.TxEUtraTDD.tddSpecialSFConfig = 0; - txParams.TxEUtraTDD.tddCPLengthDL = ORI_tddCPLength_Normal; - printf("AW2S: Configuring for TDD, EARFCN %u, Power %d, BW %d\n", + printf("AW2S: Configuring for LTE TDD, EARFCN %u, Power %d, BW %d\n", txParams.TxEUtraTDD.earfcn,txParams.TxEUtraTDD.maxTxPwr,txParams.TxEUtraTDD.chanBW); } + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) { + txParams.TxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); + txParams.TxNRTDD.axcW = 1; + txParams.TxNRTDD.axcB = 0; + txParams.TxNRTDD.chanBW = openair0_cfg->tx_bw/100e3; + txParams.TxNRTDD.AWS_arfcn = to_nrarfcn(openair0_cfg->nr_band,(long long int)openair0_cfg->tx_freq[0],openair0_cfg->nr_scs_for_raster,(uint32_t)openair0_cfg->tx_bw); + txParams.TxNRTDD.maxTxPwr = 430-((int)openair0_cfg->tx_gain[0]*10); + + printf("AW2S: Configuring for NR TDD, NRARFCN %u, Power %d, BW %d\n", + txParams.TxNRTDD.AWS_arfcn,txParams.TxNRTDD.maxTxPwr,txParams.TxNRTDD.chanBW); + } else { aw2s_oricleanup(device); return -1; @@ -499,28 +605,51 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx0, &RE_result); if(RE_result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (txParams0.TxEUtraFDD/TDD) failed with error: %s (%s,%s,%s,%s,%s,%s,%s,%s,%s\n", ORI_Result_Print(result), + printf("ORI_ObjectCreation (txParams0.TxEUtra/NRFDD/TDD) failed with error: %s (%s,%s,%s,%s,%s,%s\n", ORI_Result_Print(RE_result), ORI_Result_Print(txParamResult[0]), ORI_Result_Print(txParamResult[1]), ORI_Result_Print(txParamResult[2]), ORI_Result_Print(txParamResult[3]), ORI_Result_Print(txParamResult[4]), - ORI_Result_Print(txParamResult[5]), - ORI_Result_Print(txParamResult[6]), - ORI_Result_Print(txParamResult[7]), - ORI_Result_Print(txParamResult[8])); + ORI_Result_Print(txParamResult[5])); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (txParams0.TxEUtraFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (txParams0.TxEUtra/NRFDD/TDD): %s\n", ORI_Result_Print(RE_result)); /* Create tx1 */ if (openair0_cfg->tx_num_channels > 1) { ORI_Object_s * tx1; - if (openair0_cfg->duplex_mode ==duplex_mode_FDD) txParams.TxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); - else txParams.TxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + txParams.TxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + txParams.TxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx1, &RE_result); + if(RE_result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + } + + if (openair0_cfg->tx_num_channels > 2) { + ORI_Object_s * tx2; + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + txParams.TxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + txParams.TxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx2, &RE_result); if(RE_result != ORI_Result_SUCCESS) { printf("ORI_ObjectCreation (txParams1.TxEUtraFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); @@ -529,7 +658,25 @@ int aw2s_oriinit(openair0_device *device) { } printf("ORI_ObjectCreation (txParams1.TxEUtraFDD/TDD): %s\n", ORI_Result_Print(RE_result)); } - + if (openair0_cfg->tx_num_channels == 4) { + ORI_Object_s * tx3; + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + txParams.TxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + txParams.TxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + txParams.TxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx3, &RE_result); + if(RE_result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectCreation (txParams3.TxEUtra/NRFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + } /******************************************************************* @@ -537,42 +684,55 @@ int aw2s_oriinit(openair0_device *device) { *******************************************************************/ /* Prepare parameters */ - ORI_ObjectTypeRef_s rxTypeRef = { NULL, openair0_cfg->duplex_mode == duplex_mode_FDD ? ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD}; - ORI_ObjectParams_u rxParams,rxParams1; - ORI_ObjectParam_e rxParamList[8] = { ORI_ObjectParam_SigPath_antPort, ORI_ObjectParam_SigPath_axcW, ORI_ObjectParam_SigPath_axcB, + ORI_ObjectTypeRef_s rxTypeRef = { NULL, openair0_cfg->duplex_mode == duplex_mode_FDD ? + (openair0_cfg->nr_flag == 0 ? ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxNRFDD ) : + (openair0_cfg->nr_flag == 0 ? ORI_ObjectType_RxEUtraTDD : ORI_ObjectType_RxNRTDD)}; + ORI_ObjectParams_u rxParams; + ORI_ObjectParam_e rxParamList[5] = { ORI_ObjectParam_SigPath_antPort, ORI_ObjectParam_SigPath_axcW, ORI_ObjectParam_SigPath_axcB, ORI_ObjectParam_SigPath_chanBW, ORI_ObjectParam_SigPath_earfcn }; - ORI_Result_e rxParamResult[8]; + ORI_Result_e rxParamResult[5]; int num_rxparams = 5; - if (openair0_cfg->duplex_mode == duplex_mode_TDD) { - rxParamList[5] = ORI_ObjectParam_SigPath_tddULDLConfig; - rxParamList[6] = ORI_ObjectParam_SigPath_tddSpecialSFConfig; - rxParamList[7] = ORI_ObjectParam_RxSigPath_tddCPLengthUL; - num_rxparams = 8; - } /* Create rx0 */ ORI_Object_s * rx0; - if (openair0_cfg->duplex_mode == duplex_mode_FDD) { + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) { rxParams.RxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); rxParams.RxEUtraFDD.axcW = 1; rxParams.RxEUtraFDD.axcB = 0; - rxParams.RxEUtraFDD.chanBW = 200; - rxParams.RxEUtraFDD.earfcn = 21350; + rxParams.RxEUtraFDD.chanBW = txParams.TxEUtraFDD.chanBW; + rxParams.RxEUtraFDD.earfcn = to_earfcn_UL_aw2s(-1,(long long int)openair0_cfg->rx_freq[0],txParams.TxEUtraFDD.chanBW); result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx0, &RE_result); } - else { + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) { + rxParams.RxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); + rxParams.RxNRFDD.axcW = 1; + rxParams.RxNRFDD.axcB = 0; + rxParams.RxNRFDD.chanBW = txParams.TxNRFDD.chanBW; + rxParams.RxNRFDD.AWS_arfcn = to_nrarfcn(openair0_cfg->nr_band,(long long int)openair0_cfg->rx_freq[0],openair0_cfg->nr_scs_for_raster,openair0_cfg->rx_bw); + result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx0, &RE_result); + } + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) { rxParams.RxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); rxParams.RxEUtraTDD.axcW = 1; rxParams.RxEUtraTDD.axcB = 0; rxParams.RxEUtraTDD.chanBW = txParams.TxEUtraTDD.chanBW; rxParams.RxEUtraTDD.earfcn = txParams.TxEUtraTDD.earfcn; - rxParams.RxEUtraTDD.tddULDLConfig = 1; - rxParams.RxEUtraTDD.tddSpecialSFConfig = 1; - rxParams.RxEUtraTDD.tddCPLengthUL = ORI_tddCPLength_Normal; printf("AW2S: Creating RX0 for EARFCN %d\n",rxParams.RxEUtraTDD.earfcn); result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx0, &RE_result); + } + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) { + rxParams.RxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 0, NULL); + rxParams.RxNRTDD.axcW = 1; + rxParams.RxNRTDD.axcB = 0; + rxParams.RxNRTDD.chanBW = txParams.TxNRTDD.chanBW; + rxParams.RxNRTDD.AWS_arfcn = txParams.TxNRTDD.AWS_arfcn; + + printf("AW2S: Creating RX0 for NRARFCN %d\n",rxParams.RxNRTDD.AWS_arfcn); + + result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx0, &RE_result); + } if(result != ORI_Result_SUCCESS) @@ -581,27 +741,78 @@ int aw2s_oriinit(openair0_device *device) { aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (rxParams0.RxEUtraFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (rxParams0.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); if (openair0_cfg->rx_num_channels > 1) { /* Create rx1 */ ORI_Object_s * rx1; - memcpy((void*)&rxParams1,(void*)&rxParams,sizeof(rxParams)); - if (openair0_cfg->duplex_mode == duplex_mode_FDD) rxParams1.RxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); - else rxParams1.RxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 1, NULL); - result = ORI_ObjectCreation(ori, rxTypeRef, rxParams1, rxParamList, num_rxparams, rxParamResult, &rx1, &RE_result); + result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx1, &RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (rxParams1.RxEUtraFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (rxParams1.RxEUtraFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); } + if (openair0_cfg->rx_num_channels > 2) { + /* Create rx2 */ + ORI_Object_s * rx2; + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 2, NULL); + + result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx2, &RE_result); + + + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); + } + if (openair0_cfg->rx_num_channels > 3) { + /* Create rx3 */ + ORI_Object_s * rx3; + if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_FDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRFDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 0) + rxParams.RxEUtraTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + else if (openair0_cfg->duplex_mode == duplex_mode_TDD && openair0_cfg->nr_flag == 1) + rxParams.RxNRTDD.antPort = ORI_FindObject(ori, ORI_ObjectType_AntennaPort, 3, NULL); + + result = ORI_ObjectCreation(ori, rxTypeRef, rxParams, rxParamList, num_rxparams, rxParamResult, &rx3, &RE_result); + + + if(result != ORI_Result_SUCCESS) + { + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + aw2s_oricleanup(device); + return -1; + } + printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); + } /* Create link */ ORI_ObjectParams_u linkParams; diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 0c71a9999a..5c6ff2c669 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -237,6 +237,12 @@ typedef struct { double tx_sample_rate; //! check for threequarter sampling rate int8_t threequarter_fs; + //! Flag to indicate this configuration is for NR + int nr_flag; + //! NR band number + int nr_band; + //! NR scs for raster + int nr_scs_for_raster; } openair0_config_t; /*! \brief RF mapping */ From 4756c5a167391b019341b97b5dff7484de250eaa Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 13 Feb 2022 22:15:48 +0100 Subject: [PATCH 036/226] added configurable "sf_ahead" for NR/LTE in RU section. Tested in NR with sf_ahead=2 (normally 3) --- executables/nr-gnb.c | 1 - executables/nr-ru.c | 17 +++++++---------- executables/nr-softmodem.c | 6 +++++- nfapi/oai_integration/nfapi_vnf.c | 8 ++++---- nfapi/open-nFAPI/pnf/src/pnf_p7.c | 3 +-- openair1/PHY/defs_RU.h | 2 ++ openair2/ENB_APP/enb_paramdef.h | 7 +++++-- openair2/LAYER2/NR_MAC_gNB/config.c | 3 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 5 +++-- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 10 ++++------ openair2/NR_PHY_INTERFACE/NR_IF_Module.h | 1 + openair2/PHY_INTERFACE/IF_Module.c | 2 +- targets/RT/USER/lte-enb.c | 14 ++++++-------- targets/RT/USER/lte-ru.c | 18 +++++++++--------- targets/RT/USER/lte-softmodem.c | 1 - 15 files changed, 49 insertions(+), 49 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 2b1c36407b..da76e07741 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -129,7 +129,6 @@ void rx_func(void *param) { int slot_rx = info->slot_rx; int frame_tx = info->frame_tx; int slot_tx = info->slot_tx; - sl_ahead = sf_ahead*gNB->frame_parms.slots_per_subframe; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; start_meas(&softmodem_stats_rxtx_sf); diff --git a/executables/nr-ru.c b/executables/nr-ru.c index e4fc3bc27c..5de1f71efd 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -99,9 +99,6 @@ int attach_rru(RU_t *ru); int connect_rau(RU_t *ru); static void NRRCconfig_RU(void); -uint16_t sf_ahead; -uint16_t slot_ahead; -uint16_t sl_ahead; extern int emulate_rf; extern int numerology; @@ -372,8 +369,8 @@ void fh_if4p5_south_in(RU_t *ru, proc->frame_rx = f; proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0); // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); - proc->tti_tx = (sl+(fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; - proc->frame_tx = (sl>(fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (f+1)&1023 : f; + proc->tti_tx = (sl+(fp->slots_per_subframe*ru->sf_ahead))%fp->slots_per_frame; + proc->frame_tx = (sl>(fp->slots_per_frame-1-(fp->slots_per_subframe*ru->sf_ahead))) ? (f+1)&1023 : f; if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { @@ -1293,8 +1290,7 @@ void *ru_thread( void *param ) { } } - sf_ahead = (uint16_t) ceil((float)6/(0x01<numerology_index)); - LOG_I(PHY, "Signaling main thread that RU %d is ready, sf_ahead %d\n",ru->idx,sf_ahead); + LOG_I(PHY, "Signaling main thread that RU %d is ready, sf_ahead %d\n",ru->idx,ru->sf_ahead); pthread_mutex_lock(&RC.ru_mutex); RC.ru_mask &= ~(1<idx); pthread_cond_signal(&RC.ru_cond); @@ -1380,9 +1376,9 @@ void *ru_thread( void *param ) { opp_enabled = opp_enabled0; } if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul); - proc->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); - proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - proc->tti_tx = (proc->tti_rx + (fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; + proc->timestamp_tx = proc->timestamp_rx + (ru->sf_ahead*fp->samples_per_subframe); + proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*ru->sf_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + proc->tti_tx = (proc->tti_rx + (fp->slots_per_subframe*ru->sf_ahead))%fp->slots_per_frame; LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n", frame,slot, proc->frame_rx,proc->tti_rx, @@ -2126,6 +2122,7 @@ static void NRRCconfig_RU(void) { RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr); RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr); RC.ru[j]->do_precoding = *(RUParamList.paramarray[j][RU_DO_PRECODING].iptr); + RC.ru[j]->sf_ahead = *(RUParamList.paramarray[j][RU_SF_AHEAD].iptr); RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 5f57919645..6d59137f80 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -764,7 +764,7 @@ int main( int argc, char **argv ) { printf("wait_gNBs()\n"); wait_gNBs(); printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); - + int sl_ahead=6; if (RC.nb_RU >0) { printf("Initializing RU threads\n"); init_NR_RU(get_softmodem_params()->rf_config_file); @@ -772,7 +772,10 @@ int main( int argc, char **argv ) { for (ru_id=0; ru_idrf_map.card=0; RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset; + if (ru_id==0) sl_ahead = RC.ru[ru_id]->sf_ahead * RC.gNB[0]->frame_parms.slots_per_subframe; + else AssertFatal(RC.ru[ru_id]->sf_ahead != RC.ru[0]->sf_ahead,"RU %d has different sf_ahead %d than RU 0 %d\n",RC.ru[ru_id]->sf_ahead,RC.ru[0]->sf_ahead); } + } config_sync_var=0; @@ -789,6 +792,7 @@ int main( int argc, char **argv ) { // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration) printf("ALL RUs ready - init gNBs\n"); + for (int idx=0;idxif_inst->sl_ahead = sl_ahead; if(IS_SOFTMODEM_DOSCOPE) { sleep(1); scopeParms_t p; diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index 44ee05940f..87fd3c8e19 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -200,7 +200,6 @@ void install_nr_schedule_handlers(NR_IF_Module_t *if_inst); void install_schedule_handlers(IF_Module_t *if_inst); extern int single_thread_flag; extern uint16_t sf_ahead; -extern uint16_t slot_ahead; void oai_create_enb(void) { int bodge_counter=0; @@ -459,6 +458,7 @@ int wake_gNB_rxtx(PHY_VARS_gNB *gNB, uint16_t sfn, uint16_t slot) { //wait.tv_nsec = 0; // wake up TX for subframe n+sf_ahead // lock the TX mutex and make sure the thread is ready + AssertFatal(gNB->if_inst->sl_ahead==6,"gNB->if_inst->sl_ahead %d : This is hard-coded to 6 in nfapi P7!!!\n",gNB->if_inst->sl_ahead); if (pthread_mutex_timedlock(&L1_proc->mutex,&wait) != 0) { LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", L1_proc->slot_rx&1,L1_proc->instance_cnt ); exit_fun( "error locking mutex_rxtx" ); @@ -485,11 +485,11 @@ int wake_gNB_rxtx(PHY_VARS_gNB *gNB, uint16_t sfn, uint16_t slot) { // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, // we want to generate subframe (n+N), so TS_tx = TX_rx+N*samples_per_tti, // and proc->subframe_tx = proc->subframe_rx+sf_ahead - L1_proc->timestamp_tx = proc->timestamp_rx + (slot_ahead *fp->samples_per_subframe); + L1_proc->timestamp_tx = proc->timestamp_rx + (gNB->if_inst->sl_ahead *fp->samples_per_subframe); L1_proc->frame_rx = proc->frame_rx; L1_proc->slot_rx = proc->slot_rx; - L1_proc->frame_tx = (L1_proc->slot_rx > (19-slot_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->slot_tx = (L1_proc->slot_rx + slot_ahead)%20; + L1_proc->frame_tx = (L1_proc->slot_rx > (19-gNB->if_inst->sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + gNB->if_inst->sl_ahead)%20; //LOG_I(PHY, "sfn/sf:%d%d proc[rx:%d%d] rx:%d%d] About to wake rxtx thread\n\n", sfn, slot, proc->frame_rx, proc->slot_rx, L1_proc->frame_rx, L1_proc->slot_rx); //NFAPI_TRACE(NFAPI_TRACE_INFO, "\nEntering wake_gNB_rxtx sfn %d slot %d\n",L1_proc->frame_rx,L1_proc->slot_rx); diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c index fb1a713e56..0ce847a735 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c @@ -32,7 +32,6 @@ #define FAPI2_IP_DSCP 0 extern uint16_t sf_ahead; -extern uint16_t slot_ahead; //uint16_t sf_ahead=4; @@ -933,7 +932,7 @@ int pnf_p7_slot_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn, uint16_t sl // save the curren time, sfn and slot pnf_p7->slot_start_time_hr = pnf_get_current_time_hr(); - slot_ahead = 6; + int slot_ahead = 6; uint32_t sfn_slot_tx = sfnslot_add_slot(sfn, slot, slot_ahead); uint16_t sfn_tx = NFAPI_SFNSLOT2SFN(sfn_slot_tx); uint8_t slot_tx = NFAPI_SFNSLOT2SLOT(sfn_slot_tx); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 76dd92ef5d..5dfb0722db 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -506,6 +506,8 @@ typedef struct RU_t_s { int att_tx; /// flag to indicate precoding operation in RU int do_precoding; + /// TX processing advance in subframes + int sf_ahead; /// FAPI confiuration nfapi_nr_config_request_scf_t config; /// Frame parameters diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 2757e408d9..840e1a8ab2 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -99,6 +99,7 @@ typedef enum { #define CONFIG_STRING_RU_IF_FREQUENCY "if_freq" #define CONFIG_STRING_RU_IF_FREQ_OFFSET "if_offset" #define CONFIG_STRING_RU_DO_PRECODING "do_precoding" +#define CONFIG_STRING_RU_SF_AHEAD "sf_ahead" #define CONFIG_STRING_RU_NR_FLAG "nr_flag" #define CONFIG_STRING_RU_NR_SCS_FOR_RASTER "nr_scs_for_raster" @@ -131,8 +132,9 @@ typedef enum { #define RU_IF_FREQUENCY 26 #define RU_IF_FREQ_OFFSET 27 #define RU_DO_PRECODING 28 -#define RU_NR_FLAG 29 -#define RU_NR_SCS_FOR_RASTER 30 +#define RU_SF_AHEAD 29 +#define RU_NR_FLAG 30 +#define RU_NR_SCS_FOR_RASTER 31 /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* RU configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -167,6 +169,7 @@ typedef enum { {CONFIG_STRING_RU_IF_FREQUENCY, NULL, 0, u64ptr:NULL, defuintval:0, TYPE_UINT64, 0}, \ {CONFIG_STRING_RU_IF_FREQ_OFFSET, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_DO_PRECODING, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_SF_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_FLAG, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index bbec4817bd..92db25178a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -423,7 +423,6 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts } -extern uint16_t sl_ahead; int rrc_mac_config_req_gNB(module_id_t Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts, @@ -453,7 +452,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, * variable sl_ahead seems to not be correctly initialized, but I leave * it for information purposes here (the fix would always put 0, what * happens now, too) */ - req->SFN = i < sl_ahead; + req->SFN = i < RC.nrmac[Mod_idP]->if_inst->sl_ahead; req->Slot = i; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 0c935eea09..4ddffc5184 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -400,7 +400,7 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot, uint16_t monitoring_slot_period, uint16_t monitoring_offset,uint8_t beam_index, uint8_t num_active_ssb, - int16_t *tdd_beam_association){ + int16_t *tdd_beam_association, int sl_ahead){ // preferentially we schedule the msg2 in the mixed slot or in the last dl slot // if they are allowed by search space configuration @@ -628,7 +628,8 @@ void nr_initiate_ra_proc(module_id_t module_idP, monitoring_offset, beam_index, cc->num_active_ssb, - nr_mac->tdd_beam_association); + nr_mac->tdd_beam_association, + nr_mac->if_inst->sl_ahead); ra->Msg2_frame = msg2_frame; ra->Msg2_slot = msg2_slot; diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 57bb411dcc..46394e7c7a 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -57,8 +57,6 @@ extern int oai_nfapi_nr_srs_indication(nfapi_nr_srs_indication_t *ind); extern int oai_nfapi_nr_uci_indication(nfapi_nr_uci_indication_t *ind); extern int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind); extern uint8_t nfapi_mode; -extern uint16_t sf_ahead; -extern uint16_t sl_ahead; void handle_nr_rach(NR_UL_IND_t *UL_info) @@ -472,14 +470,14 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { nfapi_nr_config_request_scf_t *cfg = &mac->config[CC_id]; int spf = get_spf(cfg); gNB_dlsch_ulsch_scheduler(module_id, - (UL_info->frame+((UL_info->slot>(spf-1-sl_ahead))?1:0)) % 1024, - (UL_info->slot+sl_ahead)%spf); + (UL_info->frame+((UL_info->slot>(spf-1-ifi->sl_ahead))?1:0)) % 1024, + (UL_info->slot+ifi->sl_ahead)%spf); ifi->CC_mask = 0; sched_info->module_id = module_id; sched_info->CC_id = CC_id; - sched_info->frame = (UL_info->frame + ((UL_info->slot>(spf-1-sl_ahead)) ? 1 : 0)) % 1024; - sched_info->slot = (UL_info->slot+sl_ahead)%spf; + sched_info->frame = (UL_info->frame + ((UL_info->slot>(spf-1-ifi->sl_ahead)) ? 1 : 0)) % 1024; + sched_info->slot = (UL_info->slot+ifi->sl_ahead)%spf; sched_info->DL_req = &mac->DL_req[CC_id]; sched_info->UL_dci_req = &mac->UL_dci_req[CC_id]; diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h index f857151763..9d543b0918 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h @@ -115,6 +115,7 @@ typedef struct NR_IF_Module_s { uint16_t current_frame; uint8_t current_slot; pthread_mutex_t if_mutex; + int sl_ahead; } NR_IF_Module_t; /*Initial */ diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index fba9e1d8b6..68d390f097 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -16,7 +16,7 @@ extern int oai_nfapi_cqi_indication(nfapi_cqi_indication_t *cqi_ind); extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind); extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind); -extern uint16_t sf_ahead; +int sf_ahead=4; extern UL_RCC_IND_t UL_RCC_INFO; extern RAN_CONTEXT_t RC; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 0b6b0b3a75..49f7db2867 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -112,8 +112,6 @@ extern int transmission_mode; extern int oaisim_flag; -//uint16_t sf_ahead=4; -extern uint16_t sf_ahead; #include "executables/thread-common.h" //extern PARALLEL_CONF_t get_thread_parallel_conf(void); //extern WORKER_CONF_t get_thread_worker_conf(void); @@ -466,11 +464,11 @@ void eNB_top(PHY_VARS_eNB *eNB, if (!oai_exit) { T(T_ENB_MASTER_TICK, T_INT(0), T_INT(ru_proc->frame_rx), T_INT(ru_proc->tti_rx)); - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (ru->sf_ahead*fp->samples_per_tti); L1_proc->frame_rx = ru_proc->frame_rx; L1_proc->subframe_rx = ru_proc->tti_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; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-ru->sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + ru->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); @@ -614,11 +612,11 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB, // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, // and proc->subframe_tx = proc->subframe_rx+sf_ahead - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (ru->sf_ahead*fp->samples_per_tti); L1_proc->frame_rx = ru_proc->frame_rx; L1_proc->subframe_rx = ru_proc->tti_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; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-ru->sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + ru->sf_ahead)%10; LOG_D(PHY,"wakeup_rxtx: L1_proc->subframe_rx %d, L1_proc->subframe_tx %d, RU %d\n",L1_proc->subframe_rx,L1_proc->subframe_tx,ru->idx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->frame_rx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->subframe_rx); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 8ad610f1af..014e8854e2 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -109,7 +109,6 @@ const char ru_states[6][9] = {"RU_IDLE","RU_CONFIG","RU_READY","RU_RUN","RU_ERRO extern const char NB_functions[7][20]; extern const char NB_timing[2][20]; -extern uint16_t sf_ahead; extern const char ru_if_types[MAX_RU_IF_TYPES][20]; @@ -254,8 +253,8 @@ void fh_if4p5_south_in(RU_t *ru, // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti); if (get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { - proc->tti_tx = (sf+sf_ahead)%10; - proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f; + proc->tti_tx = (sf+ru->sf_ahead)%10; + proc->frame_tx = (sf>(9-ru->sf_ahead)) ? (f+1)&1023 : f; } LOG_D(PHY,"Setting proc for (%d,%d)\n",sf,f); @@ -654,13 +653,13 @@ void rx_rf(RU_t *ru, if (get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD && ru->fh_north_asynch_in == NULL) { #ifdef PHY_TX_THREAD - proc->timestamp_phy_tx = proc->timestamp_rx+((sf_ahead-1)*fp->samples_per_tti); - proc->subframe_phy_tx = (proc->tti_rx+(sf_ahead-1))%10; - proc->frame_phy_tx = (proc->tti_rx>(9-(sf_ahead-1))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + proc->timestamp_phy_tx = proc->timestamp_rx+((ru->sf_ahead-1)*fp->samples_per_tti); + proc->subframe_phy_tx = (proc->tti_rx+(ru->sf_ahead-1))%10; + proc->frame_phy_tx = (proc->tti_rx>(9-(ru->sf_ahead-1))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; #else - proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); - proc->tti_tx = (proc->tti_rx+sf_ahead)%10; - proc->frame_tx = (proc->tti_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + proc->timestamp_tx = proc->timestamp_rx+(ru->sf_ahead*fp->samples_per_tti); + proc->tti_tx = (proc->tti_rx+ru->sf_ahead)%10; + proc->frame_tx = (proc->tti_rx>(9-ru->sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; #endif //proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); //proc->subframe_tx = (proc->tti_rx+sf_ahead)%10; @@ -3072,6 +3071,7 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); + ru[j]->sf_ahead = *(RUParamList.paramarray[j][RU_SF_AHEAD_IDX].uptr); *ru_mask= (*ru_mask)|(1< Date: Thu, 17 Feb 2022 10:16:22 +0100 Subject: [PATCH 037/226] TBSLBRM for DL computed ad MAC (added fapi parameter) --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 5 ++ openair1/PHY/CODING/coding_defs.h | 4 -- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 7 +-- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 6 +-- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 7 +-- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 1 + .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 8 +-- openair1/PHY/defs_gNB.h | 1 - openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 1 + .../NR_MAC_COMMON/nr_compute_tbs_common.c | 51 +++++++++---------- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 22 ++++++++ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 7 +++ openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 15 ++++++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 10 ++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 4 ++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 14 ++++- 17 files changed, 106 insertions(+), 59 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 3b429a5e84..9e051e0a48 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -464,7 +464,7 @@ typedef struct { uint8_t nEpreRatioOfPDSCHToPTRS; /// MCS table for this DLSCH uint8_t mcs_table; - + uint32_t tbslbrm; uint16_t pduBitmap; } fapi_nr_dl_config_dlsch_pdu_rel15_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index c3a173758c..ee680f7fc7 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -776,6 +776,10 @@ typedef struct { nfapi_nr_dl_dci_pdu_t dci_pdu[MAX_DCI_CORESET]; } nfapi_nr_dl_tti_pdcch_pdu_rel15_t; +typedef struct { + uint32_t tbSizeLbrmBytes; +}nfapi_v3_pdsch_maintenance_parameters_t; + typedef struct { uint16_t pduBitmap; uint16_t rnti; @@ -854,6 +858,7 @@ typedef struct { uint8_t nEpreRatioOfPDSCHToPTRS; // Beamforming nfapi_nr_tx_precoding_and_beamforming_t precodingAndBeamforming; + nfapi_v3_pdsch_maintenance_parameters_t maintenance_parms_v3; }nfapi_nr_dl_tti_pdsch_pdu_rel15_t; diff --git a/openair1/PHY/CODING/coding_defs.h b/openair1/PHY/CODING/coding_defs.h index 8fe31f208e..f6aba66830 100644 --- a/openair1/PHY/CODING/coding_defs.h +++ b/openair1/PHY/CODING/coding_defs.h @@ -481,10 +481,6 @@ uint32_t nr_compute_tbs(uint16_t Qm, uint8_t tb_scaling, uint8_t Nl); -uint32_t nr_compute_tbslbrm(uint16_t table, - uint16_t nb_rb, - uint8_t Nl); - void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f); void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 6d16fa531c..14de9ed767 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -229,13 +229,8 @@ void ldpc8blocks( void *p) { impp->F, Kr-impp->F-2*(*impp->Zc), mod_order,nb_rb); - // for tbslbrm calculation according to 5.4.2.1 of 38.212 - uint8_t Nl = 4; - if (rel15->nrOfLayers < Nl) - Nl = rel15->nrOfLayers; - - uint32_t Tbslbrm = nr_compute_tbslbrm(rel15->mcsTable[0],nb_rb,Nl); + uint32_t Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; uint8_t Ilbrm = 1; uint8_t e[E]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 31d44736d4..250a243af1 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -259,7 +259,6 @@ void nr_processULSegment(void* arg) { int rv_index = rdata->rv_index; int r_offset = rdata->r_offset; uint8_t kc = rdata->Kc; - uint32_t Tbslbrm = rdata->Tbslbrm; short* ulsch_llr = rdata->ulsch_llr; int max_ldpc_iterations = p_decoderParms->numMaxIter; int8_t llrProcBuf[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))); @@ -319,7 +318,7 @@ void nr_processULSegment(void* arg) { //start_meas(&phy_vars_gNB->ulsch_rate_unmatching_stats); if (nr_rate_matching_ldpc_rx(Ilbrm, - Tbslbrm, + 0, p_decoderParms->BG, p_decoderParms->Z, ulsch_harq->d[r], @@ -420,7 +419,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, uint32_t r_offset; uint32_t offset; int kc; - int Tbslbrm; int E; #ifdef PRINT_CRC_CHECK @@ -559,7 +557,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, if (!frame%100) printf("K %d C %d Z %d \n", harq_process->K, harq_process->C, harq_process->Z); #endif - Tbslbrm = nr_compute_tbslbrm(0,nb_rb,n_layers); p_decParams->Z = harq_process->Z; @@ -610,7 +607,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, rdata->r_offset = r_offset; rdata->Kr_bytes = Kr_bytes; rdata->rv_index = pusch_pdu->pusch_data.rv_index; - rdata->Tbslbrm = Tbslbrm; rdata->offset = offset; rdata->ulsch = ulsch; rdata->ulsch_id = ULSCH_id; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 8064093eed..32848951c2 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -472,7 +472,6 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, phy_vars_ue->dl_stats[harq_process->round]++; LOG_D(PHY,"Round %d RV idx %d\n",harq_process->round,harq_process->rvidx); uint8_t kc; - uint32_t Tbslbrm;// = 950984; uint16_t nb_rb;// = 30; double Coderate;// = 0.0; uint8_t dmrs_Type = harq_process->dmrsConfigType; @@ -583,10 +582,6 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!frame%100)) LOG_I(PHY,"K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, p_decParams->Z, harq_process->Nl); } - if ((harq_process->Nl)<4) - Tbslbrm = nr_compute_tbslbrm(harq_process->mcs_table,nb_rb,harq_process->Nl); - else - Tbslbrm = nr_compute_tbslbrm(harq_process->mcs_table,nb_rb,4); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); p_decParams->Z = harq_process->Z; @@ -637,7 +632,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, rdata->r_offset = r_offset; rdata->Kr_bytes = Kr_bytes; rdata->rv_index = harq_process->rvidx; - rdata->Tbslbrm = Tbslbrm; + rdata->Tbslbrm = harq_process->tbslbrm; rdata->offset = offset; rdata->dlsch = dlsch; rdata->dlsch_id = 0; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 9b9f1add6e..7048c97189 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -303,6 +303,7 @@ typedef struct { uint16_t ptrs_symbols; // PTRS symbol index, to be updated every PTRS symbol within a slot. uint8_t ptrs_symbol_index; + uint32_t tbslbrm; /// PDU BITMAP uint16_t pduBitmap; } NR_DL_UE_HARQ_t; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 553d4fa4f7..91e14fdfd4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -233,8 +233,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, uint16_t Kr,r; uint32_t r_offset; uint32_t E,Kb; - uint8_t Ilbrm; - uint32_t Tbslbrm; + uint8_t Ilbrm; uint16_t R; float Coderate; @@ -256,7 +255,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, r_offset=0; F=0; Ilbrm = 0; - Tbslbrm = 950984; //max tbs Coderate = 0.0; /////////// ///////////////////////////////////////////////////////////////////////////////////////// @@ -440,12 +438,10 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, E = nr_get_E(G, harq_process->C, mod_order, harq_process->pusch_pdu.nrOfLayers, r); - Tbslbrm = nr_compute_tbslbrm(0,nb_rb,harq_process->pusch_pdu.nrOfLayers); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN); start_meas(&ue->ulsch_rate_matching_stats); if (nr_rate_matching_ldpc(Ilbrm, - Tbslbrm, + 0, harq_process->BG, *pz, harq_process->d[r], diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 7c7d30a6e2..5e3a541d20 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -928,7 +928,6 @@ typedef struct LDPCDecode_s { int segment_r; int r_offset; int offset; - int Tbslbrm; int decodeIterations; } ldpcDecode_t; diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 4f4757ec5a..c8386b881e 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -286,6 +286,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ dlsch0_harq->n_dmrs_cdm_groups = dlsch_config_pdu->n_dmrs_cdm_groups; dlsch0_harq->mcs = dlsch_config_pdu->mcs; dlsch0_harq->rvidx = dlsch_config_pdu->rv; + dlsch0_harq->tbslbrm = dlsch_config_pdu->tbslbrm; dlsch0->g_pucch = dlsch_config_pdu->accumulated_delta_PUCCH; //get nrOfLayers from DCI info uint8_t Nl = 0; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c index 4fcbd322db..b07659a0ea 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c @@ -92,12 +92,10 @@ uint32_t nr_compute_tbs(uint16_t Qm, } - //tbslbrm calculation according to 5.4.2.1 of 38.212 uint32_t nr_compute_tbslbrm(uint16_t table, uint16_t nb_rb, - uint8_t Nl) -{ + uint8_t Nl) { uint16_t R, nb_re; uint16_t nb_rb_lbrm=0; @@ -122,34 +120,31 @@ uint32_t nr_compute_tbslbrm(uint16_t table, Ninfo = (nb_re * R * Qm * Nl)>>10; if (Ninfo <=3824) { - n = max(3, floor(log2(Ninfo)) - 6); - Np_info = max(24, (Ninfo>>n)<= Np_info){ - nr_tbs = Tbstable_nr[i]; - break; - } - } + n = max(3, floor(log2(Ninfo)) - 6); + Np_info = max(24, (Ninfo>>n)<= Np_info){ + nr_tbs = Tbstable_nr[i]; + break; + } + } } else { - n = log2(Ninfo-24)-5; - Np_info = max(3840, (ROUNDIDIV((Ninfo-24),(1< 8424){ - C = CEILIDIV((Np_info+24),8424); - nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; - } - else { - nr_tbs = ((CEILIDIV((Np_info+24),8))<<3) - 24; - } - - } + n = log2(Ninfo-24)-5; + Np_info = max(3840, (ROUNDIDIV((Ninfo-24),(1< 8424){ + C = CEILIDIV((Np_info+24),8424); + nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; + } + else + nr_tbs = ((CEILIDIV((Np_info+24),8))<<3) - 24; + } } return nr_tbs; } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 942e3afad1..69d245e7c1 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4076,6 +4076,28 @@ uint16_t compute_pucch_prb_size(uint8_t format, } } +int get_bw_tbslbrm(NR_ServingCellConfigCommon_t *scc, + NR_CellGroupConfig_t *cg) { + + int bw = 0; + NR_BWP_t genericParameters; + if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && + cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { + struct NR_ServingCellConfig__downlinkBWP_ToAddModList *BWP_list = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; + for (int i=0; ilist.count; i++) { + genericParameters = BWP_list->list.array[i]->bwp_Common->genericParameters; + int curr_bw = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + if (curr_bw > bw) + bw = curr_bw; + } + } + else { + genericParameters = scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + bw = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + } + return bw; +} + /* extract UL PTRS values from RRC and validate it based upon 38.214 6.2.3 */ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config, uint16_t rbSize,uint8_t mcsIndex, uint8_t mcsTable, diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 91450fc796..bccc40b2c6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -121,6 +121,13 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB); uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset); +int get_bw_tbslbrm(NR_ServingCellConfigCommon_t *scc, + NR_CellGroupConfig_t *cg); + +uint32_t nr_compute_tbslbrm(uint16_t table, + uint16_t nb_rb, + uint8_t Nl); + void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, frame_t frameP, NR_MIB_t *mib, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 85bb10290a..f852da7281 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -890,6 +890,12 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr LOG_W(MAC, "[%d.%d] MCS value %d out of bounds! Possibly due to false DCI. Ignoring DCI!\n", frame, slot, dlsch_config_pdu_1_0->mcs); return -1; } + + int bw_tbslbrm = get_bw_tbslbrm(mac->scc, mac->cg); + dlsch_config_pdu_1_0->tbslbrm = nr_compute_tbslbrm(dlsch_config_pdu_1_0->mcs_table, + bw_tbslbrm, + 1); + /* NDI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ dlsch_config_pdu_1_0->ndi = dci->ndi; /* RV (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ @@ -1254,6 +1260,15 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dl_config->number_pdus = dl_config->number_pdus + 1; /* TODO same calculation for MCS table as done in UL */ dlsch_config_pdu_1_1->mcs_table = (pdsch_Config->mcs_Table) ? (*pdsch_Config->mcs_Table + 1) : 0; + + // TBS_LBRM according to section 5.4.2.1 of 38.212 + long *maxMIMO_Layers = mac->cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; + AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); + int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; + int bw_tbslbrm = get_bw_tbslbrm(mac->scc, mac->cg); + dlsch_config_pdu_1_1->tbslbrm = nr_compute_tbslbrm(dlsch_config_pdu_1_1->mcs_table, + bw_tbslbrm, + nl_tbslbrm); /*PTRS configuration */ dlsch_config_pdu_1_1->pduBitmap = 0; if(pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 4261020f76..26479b4b88 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1338,6 +1338,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint8_t tb_scaling = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); + int bw_tbslbrm = get_bw_tbslbrm(scc, ra->CellGroup); + pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, + bw_tbslbrm, + 1); + // Fill PDCCH DL DCI PDU nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; pdcch_pdu_rel15->numDlDci++; @@ -1715,6 +1720,11 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int x_Overhead = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); + int bw_tbslbrm = get_bw_tbslbrm(scc, ra->CellGroup); + pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, + bw_tbslbrm, + 1); + pdsch_pdu_rel15->precodingAndBeamforming.num_prgs=1; pdsch_pdu_rel15->precodingAndBeamforming.prg_size=275; pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces=1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 0af340725a..634d2b7d89 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -502,6 +502,10 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, pdsch_pdu_rel15->dlDmrsSymbPos = dlDmrsSymbPos; LOG_D(MAC,"dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->dlDmrsSymbPos); + pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(0, + pdsch_pdu_rel15->BWPSize, + 1); + /* Fill PDCCH DL DCI PDU */ nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; pdcch_pdu_rel15->numDlDci++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index cb76c22292..5b39f44ee2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1140,6 +1140,16 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->StartSymbolIndex = ps->startSymbolIndex; pdsch_pdu->NrOfSymbols = ps->nrOfSymbols; + // TBS_LBRM according to section 5.4.2.1 of 38.212 + long *maxMIMO_Layers = cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; + AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); + int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; + // Maximum number of PRBs across all configured DL BWPs + int bw_tbslbrm = get_bw_tbslbrm(scc, cg); + pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ps->mcsTableIdx, + bw_tbslbrm, + nl_tbslbrm); + NR_PDSCH_Config_t *pdsch_Config=NULL; if (bwp && bwp->bwp_Dedicated && @@ -1189,7 +1199,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_pdu_rel15_t dci_payload; memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); // bwp indicator - const int n_dl_bwp = bwp ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count : 0; + const int n_dl_bwp = bwp ? cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count : 0; AssertFatal(n_dl_bwp <= 1, "downlinkBWP_ToAddModList has %d BWP!\n", n_dl_bwp); // as per table 7.3.1.1.2-1 in 38.212 @@ -1242,7 +1252,7 @@ void nr_schedule_ue_spec(module_id_t module_id, const int rnti_type = NR_RNTI_C; fill_dci_pdu_rel15(scc, - UE_info->CellGroup[UE_id], + cg, dci_pdu, &dci_payload, dci_format, From 7b4b7b96196784aee9d86aa6b686cc2dfb86bfa7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 17 Feb 2022 18:13:57 +0100 Subject: [PATCH 038/226] fix for dlschsim --- openair1/SIMULATION/NR_PHY/dlschsim.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index f566b93d9c..a0dd1b433d 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -118,6 +118,7 @@ int main(int argc, char **argv) double DS_TDL = .03; cpuf = get_cpu_freq_GHz(); char gNBthreads[128]="n"; + int Tbslbrm = 950984; if (load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY) == 0) { exit_fun("[NR_DLSCHSIM] Error, configuration module init failed\n"); @@ -472,6 +473,7 @@ int main(int argc, char **argv) rel15->dlDmrsSymbPos = 4; rel15->mcsIndex[0] = Imcs; rel15->numDmrsCdmGrpsNoData = 1; + rel15->maintenance_parms_v3.tbSizeLbrmBytes = Tbslbrm; double *modulated_input = malloc16(sizeof(double) * 16 * 68 * 384); // [hna] 16 segments, 68*Zc short *channel_output_fixed = malloc16(sizeof(short) * 16 * 68 * 384); short *channel_output_uncoded = malloc16(sizeof(unsigned short) * 16 * 68 * 384); @@ -494,6 +496,7 @@ int main(int argc, char **argv) harq_process->dmrsConfigType = NFAPI_NR_DMRS_TYPE1; harq_process->dlDmrsSymbPos = 4; harq_process->n_dmrs_cdm_groups = 1; + harq_process->tbslbrm = Tbslbrm; printf("harq process ue mcs = %d Qm = %d, symb %d\n", harq_process->mcs, harq_process->Qm, nb_symb_sch); unsigned char *test_input; test_input = (unsigned char *) malloc16(sizeof(unsigned char) * TBS / 8); From 9eb1137b542deb02db65f9575d318307489b55d9 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 18 Feb 2022 10:14:52 +0100 Subject: [PATCH 039/226] fix for scc/scc_SIB at UE --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 13 +++++-------- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 13 +++++++++++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 ++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 69d245e7c1..1c40eae725 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4076,25 +4076,22 @@ uint16_t compute_pucch_prb_size(uint8_t format, } } -int get_bw_tbslbrm(NR_ServingCellConfigCommon_t *scc, +int get_bw_tbslbrm(NR_BWP_t *genericParameters, NR_CellGroupConfig_t *cg) { int bw = 0; - NR_BWP_t genericParameters; if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { struct NR_ServingCellConfig__downlinkBWP_ToAddModList *BWP_list = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; for (int i=0; ilist.count; i++) { - genericParameters = BWP_list->list.array[i]->bwp_Common->genericParameters; - int curr_bw = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + genericParameters = &BWP_list->list.array[i]->bwp_Common->genericParameters; + int curr_bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); if (curr_bw > bw) bw = curr_bw; } } - else { - genericParameters = scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - bw = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - } + else + bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); return bw; } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index bccc40b2c6..3c953226f4 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -121,7 +121,7 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB); uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset); -int get_bw_tbslbrm(NR_ServingCellConfigCommon_t *scc, +int get_bw_tbslbrm(NR_BWP_t *genericParameters, NR_CellGroupConfig_t *cg); uint32_t nr_compute_tbslbrm(uint16_t table, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index f852da7281..0ab103aaa7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -891,7 +891,14 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr return -1; } - int bw_tbslbrm = get_bw_tbslbrm(mac->scc, mac->cg); + int bw_tbslbrm; + if (mac->scc || mac->scc_SIB || mac->cg) { + NR_BWP_t genericParameters = mac->scc ? mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters : + mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters; + bw_tbslbrm = get_bw_tbslbrm(&genericParameters, mac->cg); + } + else + bw_tbslbrm = dlsch_config_pdu_1_0->BWPSize; dlsch_config_pdu_1_0->tbslbrm = nr_compute_tbslbrm(dlsch_config_pdu_1_0->mcs_table, bw_tbslbrm, 1); @@ -1265,7 +1272,9 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr long *maxMIMO_Layers = mac->cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; - int bw_tbslbrm = get_bw_tbslbrm(mac->scc, mac->cg); + NR_BWP_t genericParameters = mac->scc ? mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters : + mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters; + int bw_tbslbrm = get_bw_tbslbrm(&genericParameters, mac->cg); dlsch_config_pdu_1_1->tbslbrm = nr_compute_tbslbrm(dlsch_config_pdu_1_1->mcs_table, bw_tbslbrm, nl_tbslbrm); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 26479b4b88..44b65a5387 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1338,7 +1338,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint8_t tb_scaling = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); - int bw_tbslbrm = get_bw_tbslbrm(scc, ra->CellGroup); + int bw_tbslbrm = get_bw_tbslbrm(genericParameters, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); @@ -1720,7 +1720,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int x_Overhead = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); - int bw_tbslbrm = get_bw_tbslbrm(scc, ra->CellGroup); + int bw_tbslbrm = get_bw_tbslbrm(genericParameters, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5b39f44ee2..3557742802 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1145,7 +1145,7 @@ void nr_schedule_ue_spec(module_id_t module_id, AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; // Maximum number of PRBs across all configured DL BWPs - int bw_tbslbrm = get_bw_tbslbrm(scc, cg); + int bw_tbslbrm = get_bw_tbslbrm(genericParameters, cg); pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ps->mcsTableIdx, bw_tbslbrm, nl_tbslbrm); From 6d9d1f0b9484afb378161249691f143312b46aac Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 19 Feb 2022 13:07:20 +0100 Subject: [PATCH 040/226] changes for 2.5ms TDD period --- executables/nr-ru.c | 17 ++++++---- executables/nr-softmodem.c | 4 +-- openair1/PHY/defs_RU.h | 4 ++- openair2/ENB_APP/enb_paramdef.h | 7 ++-- openair2/GNB_APP/MACRLC_nr_paramdef.h | 8 ++++- openair2/GNB_APP/gnb_config.c | 2 ++ openair2/LAYER2/NR_MAC_gNB/config.c | 4 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 20 +++++++---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 16 ++++++++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 33 +++++++++++-------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 17 +++++++--- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 9 +++-- openair2/RRC/NR/MESSAGES/asn1_msg.c | 8 +---- openair2/RRC/NR/nr_rrc_config.c | 23 +++++++++++-- 15 files changed, 122 insertions(+), 52 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 5de1f71efd..2f74c3524b 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -369,8 +369,8 @@ void fh_if4p5_south_in(RU_t *ru, proc->frame_rx = f; proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0); // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); - proc->tti_tx = (sl+(fp->slots_per_subframe*ru->sf_ahead))%fp->slots_per_frame; - proc->frame_tx = (sl>(fp->slots_per_frame-1-(fp->slots_per_subframe*ru->sf_ahead))) ? (f+1)&1023 : f; + proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame; + proc->frame_tx = (sl>(fp->slots_per_frame-1-(ru->sl_ahead))) ? (f+1)&1023 : f; if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { @@ -1290,7 +1290,7 @@ void *ru_thread( void *param ) { } } - LOG_I(PHY, "Signaling main thread that RU %d is ready, sf_ahead %d\n",ru->idx,ru->sf_ahead); + LOG_I(PHY, "Signaling main thread that RU %d is ready, sl_ahead %d\n",ru->idx,ru->sl_ahead); pthread_mutex_lock(&RC.ru_mutex); RC.ru_mask &= ~(1<idx); pthread_cond_signal(&RC.ru_cond); @@ -1376,9 +1376,12 @@ void *ru_thread( void *param ) { opp_enabled = opp_enabled0; } if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul); - proc->timestamp_tx = proc->timestamp_rx + (ru->sf_ahead*fp->samples_per_subframe); - proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*ru->sf_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - proc->tti_tx = (proc->tti_rx + (fp->slots_per_subframe*ru->sf_ahead))%fp->slots_per_frame; + proc->timestamp_tx = proc->timestamp_rx; + int sl=proc->tti_tx; + for (int slidx=0;slidxsl_ahead;slidx++) + proc->timestamp_tx += fp->get_samples_per_slot((sl+slidx)%fp->slots_per_frame,fp); + proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(ru->sl_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + proc->tti_tx = (proc->tti_rx + ru->sl_ahead)%fp->slots_per_frame; LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n", frame,slot, proc->frame_rx,proc->tti_rx, @@ -2122,7 +2125,7 @@ static void NRRCconfig_RU(void) { RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr); RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr); RC.ru[j]->do_precoding = *(RUParamList.paramarray[j][RU_DO_PRECODING].iptr); - RC.ru[j]->sf_ahead = *(RUParamList.paramarray[j][RU_SF_AHEAD].iptr); + RC.ru[j]->sl_ahead = *(RUParamList.paramarray[j][RU_SL_AHEAD].iptr); RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 6d59137f80..dc7b8bf8e3 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -772,8 +772,8 @@ int main( int argc, char **argv ) { for (ru_id=0; ru_idrf_map.card=0; RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset; - if (ru_id==0) sl_ahead = RC.ru[ru_id]->sf_ahead * RC.gNB[0]->frame_parms.slots_per_subframe; - else AssertFatal(RC.ru[ru_id]->sf_ahead != RC.ru[0]->sf_ahead,"RU %d has different sf_ahead %d than RU 0 %d\n",RC.ru[ru_id]->sf_ahead,RC.ru[0]->sf_ahead); + if (ru_id==0) sl_ahead = RC.ru[ru_id]->sl_ahead; + else AssertFatal(RC.ru[ru_id]->sl_ahead != RC.ru[0]->sl_ahead,"RU %d has different sl_ahead %d than RU 0 %d\n",RC.ru[ru_id]->sl_ahead,RC.ru[0]->sl_ahead); } } diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 5dfb0722db..e70bb811b7 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -506,8 +506,10 @@ typedef struct RU_t_s { int att_tx; /// flag to indicate precoding operation in RU int do_precoding; - /// TX processing advance in subframes + /// TX processing advance in subframes (for LTE) int sf_ahead; + /// TX processing advance in slots (for NR) + int sl_ahead; /// FAPI confiuration nfapi_nr_config_request_scf_t config; /// Frame parameters diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 840e1a8ab2..a533b8cb23 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -100,6 +100,7 @@ typedef enum { #define CONFIG_STRING_RU_IF_FREQ_OFFSET "if_offset" #define CONFIG_STRING_RU_DO_PRECODING "do_precoding" #define CONFIG_STRING_RU_SF_AHEAD "sf_ahead" +#define CONFIG_STRING_RU_SL_AHEAD "sl_ahead" #define CONFIG_STRING_RU_NR_FLAG "nr_flag" #define CONFIG_STRING_RU_NR_SCS_FOR_RASTER "nr_scs_for_raster" @@ -133,8 +134,9 @@ typedef enum { #define RU_IF_FREQ_OFFSET 27 #define RU_DO_PRECODING 28 #define RU_SF_AHEAD 29 -#define RU_NR_FLAG 30 -#define RU_NR_SCS_FOR_RASTER 31 +#define RU_SL_AHEAD 30 +#define RU_NR_FLAG 31 +#define RU_NR_SCS_FOR_RASTER 32 /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* RU configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -170,6 +172,7 @@ typedef enum { {CONFIG_STRING_RU_IF_FREQ_OFFSET, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_DO_PRECODING, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_SF_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_SL_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_FLAG, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ } diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 436271fc0b..e634f077e2 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -65,6 +65,8 @@ #define CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD "dl_rd2_bler_threshold" #define CONFIG_STRING_MACRLC_DL_MAX_MCS "dl_max_mcs" #define CONFIG_STRING_MACRLC_HARQ_ROUND_MAX "harq_round_max" +#define CONFIG_STRING_MACRLC_MIN_GRANT_PRB "min_grant_prb" +#define CONFIG_STRING_MACRLC_MIN_GRANT_MCS "min_grant_mcs" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -97,7 +99,9 @@ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase DL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD, "Threshold of RD2/RETX2 BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.01, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_MAX_MCS, "Maximum DL MCS that should be used", 0, u8ptr:NULL, defintval:28, TYPE_UINT8, 0}, \ -{CONFIG_STRING_MACRLC_HARQ_ROUND_MAX, "Maximum number of HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0} \ +{CONFIG_STRING_MACRLC_HARQ_ROUND_MAX, "Maximum number of HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_MIN_GRANT_PRB, "Minimal Periodic ULSCH Grant PRBs", 0, u8ptr:NULL, defintval:5, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_MIN_GRANT_MCS, "Minimal Periodic ULSCH Grant MCS", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0} \ } #define MACRLC_CC_IDX 0 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 @@ -126,5 +130,7 @@ #define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24 #define MACRLC_DL_MAX_MCS_IDX 25 #define MACRLC_HARQ_ROUND_MAX_IDX 26 +#define MACRLC_MIN_GRANT_PRB_IDX 27 +#define MACRLC_MIN_GRANT_MCS_IDX 28 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 72237bf6c9..b088cf7ed1 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -811,6 +811,8 @@ void RCconfig_nr_macrlc() { RC.nrmac[j]->dl_rd2_bler_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_RD2_BLER_THRESHOLD_IDX].dblptr); RC.nrmac[j]->dl_max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr); RC.nrmac[j]->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_HARQ_ROUND_MAX_IDX].u8ptr); + RC.nrmac[j]->min_grant_prb = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_PRB_IDX].u8ptr); + RC.nrmac[j]->min_grant_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_MCS_IDX].u8ptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; memcpy(RC.nrmac[j]->ulprbbl,prbbl,275*sizeof(prbbl[0])); }// for (j=0;jnrofDownlinkSlots + (tdd->nrofUplinkSymbols == 0); for (int slot = 0; slot < n; ++slot) { - /* FIXME: it seems there is a problem with slot 0/10/slots right after UL: - * we just get retransmissions. Thus, do not schedule such slots in DL */ - if (slot % nr_slots_period != 0) + if (slot != 0) RC.nrmac[Mod_idP]->dlsch_slot_bitmap[slot / 64] |= (uint64_t)((slot % nr_slots_period) < nr_dlmix_slots) << (slot % 64); RC.nrmac[Mod_idP]->ulsch_slot_bitmap[slot / 64] |= (uint64_t)((slot % nr_slots_period) >= nr_ulstart_slot) << (slot % 64); LOG_D(NR_MAC, "slot %d DL %d UL %d\n", diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 4ddffc5184..c5ec5e04e8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -916,16 +916,23 @@ void nr_get_Msg3alloc(module_id_t module_id, int nb_slots_per_period = ((1<list.count; i++) { k2 = *pusch_TimeDomainAllocationList->list.array[i]->k2; - // we want to transmit in the uplink symbols of mixed slot + int start_symbol_index,nr_of_symbols; + SLIV2SL(pusch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength, &start_symbol_index, &nr_of_symbols); + LOG_I(NR_MAC,"Checking Msg3 TDA %d : k2 %d, sliv %d,S %d L %d\n",i,(int)k2,(int)pusch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength,start_symbol_index,nr_of_symbols); + // we want to transmit in the uplink symbols of mixed slot AND assuming Msg2 was in the mixed slot if ((k2 + DELTA[mu])%nb_slots_per_period == 0) { temp_slot = current_slot + k2 + DELTA[mu]; // msg3 slot according to 8.3 in 38.213 ra->Msg3_slot = temp_slot%nr_slots_per_frame[mu]; - if (is_xlsch_in_slot(RC.nrmac[module_id]->ulsch_slot_bitmap[ra->Msg3_slot / 64], ra->Msg3_slot)) { + + if (is_xlsch_in_slot(RC.nrmac[module_id]->ulsch_slot_bitmap[ra->Msg3_slot / 64], ra->Msg3_slot) && + nr_of_symbols<=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols&& + start_symbol_index>=(14-scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols)) { ra->Msg3_tda_id = i; break; } } } + AssertFatal(ra->Msg3_tda_id < 16, "Couldn't find an appropriate TD allocation for Msg3\n"); } else { ra->Msg3_tda_id = 0; @@ -953,7 +960,7 @@ void nr_get_Msg3alloc(module_id_t module_id, tdd_beam_association[num_tdd_period] = ra->beam_id; } - LOG_D(NR_MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id); + LOG_I(NR_MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id); uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * MAX_BWP_SIZE]; @@ -1021,7 +1028,7 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = 1; pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); - LOG_D(MAC, "MSG3 start_sym:%d NR Symb:%d mappingtype:%d , ul_dmrs_symb_pos:%x\n", start_symbol_index, nr_of_symbols, mappingtype, pusch_pdu->ul_dmrs_symb_pos); + LOG_I(MAC, "MSG3 mcs %d, nb_rb %d, first_rb %d, start_sym:%d NR Symb:%d mappingtype:%d , ul_dmrs_symb_pos:%x\n", pusch_pdu->mcs_index,msg3_nb_rb,msg3_first_rb, start_symbol_index, nr_of_symbols, mappingtype, pusch_pdu->ul_dmrs_symb_pos); pusch_pdu->dmrs_config_type = 0; pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0. @@ -1115,7 +1122,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; } - LOG_D(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", + LOG_I(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", frameP, slotP, ra->Msg3_frame, @@ -1404,8 +1411,9 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); if(ra->cfra) { - LOG_I(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception for Frame %d Subframe %d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); + LOG_I(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CFRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); } + else LOG_I(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CBRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); T(T_GNB_MAC_DL_RAR_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(ra->RA_rnti), T_INT(frameP), T_INT(slotP), T_INT(0), T_BUFFER(&tx_req->TLVs[0].value.direct[0], tx_req->TLVs[0].length)); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 689f621b86..a48a59b67b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -979,7 +979,6 @@ void nr_schedule_ue_spec(module_id_t module_id, gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; if (!is_xlsch_in_slot(gNB_mac->dlsch_slot_bitmap[slot / 64], slot)) return; - /* PREPROCESSOR */ gNB_mac->pre_processor_dl(module_id, frame, slot); @@ -1351,6 +1350,21 @@ void nr_schedule_ue_spec(module_id_t module_id, size); if (len == 0) break; + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + if (lcid>=4) + LOG_D(NR_MAC, + "%4d.%2d [UE %04x]: Time %lu.%lu: %d bytes %s %d -> DLSCH (ndata %lu, remaining size %lu)\n", + frame, + slot, + rnti, + time_request.tv_sec, + time_request.tv_nsec, + len, + lcid < 4 ? "DCCH" : "DTCH", + lcid, + (unsigned long)ndata, + (unsigned long)size); header->R = 0; header->F = 1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e54e1f203a..eb51f1ca26 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -463,12 +463,14 @@ int nr_process_mac_pdu(module_id_t module_idP, mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; mac_subheader_len = 2; } - - LOG_D(NR_MAC, "In %s: [UE %d] %d.%d : ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", - __func__, - module_idP, + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(NR_MAC, "[UE %x] %d.%d : Time %lu.%lu ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", + UE_info->rnti[UE_id], frameP, slot, + time_request.tv_sec, + time_request.tv_nsec, rx_lcid<4?"DCCH":"DTCH", rx_lcid, module_idP, @@ -711,8 +713,8 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, UE_info->mac_stats[UE_id].ulsch_DTX++; } if (UE_info->UE_sched_ctrl[UE_id].pusch_consecutive_dtx_cnt >= pusch_failure_thres) { - LOG_W(NR_MAC,"Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", - UE_info->UE_sched_ctrl[UE_id].pusch_consecutive_dtx_cnt); + LOG_W(NR_MAC,"%d.%d Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", + frameP,slotP,UE_info->UE_sched_ctrl[UE_id].pusch_consecutive_dtx_cnt); UE_info->UE_sched_ctrl[UE_id].ul_failure = 1; nr_mac_gNB_rrc_ul_failure(gnb_mod_idP,CC_idP,frameP,slotP,rntiP); } @@ -909,17 +911,22 @@ bool nr_UE_is_to_be_scheduled(module_id_t mod_id, int CC_id, int UE_id, frame_t const struct gNB_MAC_INST_s *nrmac = RC.nrmac[mod_id]; const NR_UE_sched_ctrl_t *sched_ctrl = &nrmac->UE_info.UE_sched_ctrl[UE_id]; - const int last_ul_sched = sched_ctrl->last_ul_frame * n + sched_ctrl->last_ul_slot; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; int num_slots_per_period; + int last_ul_slot,last_ul_sched; int tdd_period_len[8] = {500,625,1000,1250,2000,2500,5000,10000}; - if (tdd) + if (tdd) { // Force the default transmission in a full slot as early as possible in the UL portion of TDD period (last_ul_slot) num_slots_per_period = n*tdd_period_len[tdd->dl_UL_TransmissionPeriodicity]/10000; - else + last_ul_slot=1+tdd->nrofDownlinkSlots; + } + else { num_slots_per_period = n; + last_ul_slot = sched_ctrl->last_ul_slot; + } + last_ul_sched = sched_ctrl->last_ul_frame * n + last_ul_slot; const int diff = (now - last_ul_sched + 1024 * n) % (1024 * n); /* UE is to be scheduled if * (1) we think the UE has more bytes awaiting than what we scheduled @@ -1111,7 +1118,7 @@ void pf_ul(module_id_t module_id, gNB_MAC_INST *nrmac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; NR_UE_info_t *UE_info = &nrmac->UE_info; - const int min_rb = 5; + const int min_rb = nrmac->min_grant_prb; float coeff_ue[MAX_MOBILES_PER_GNB]; // UEs that could be scheduled int ue_array[MAX_MOBILES_PER_GNB]; @@ -1226,7 +1233,7 @@ void pf_ul(module_id_t module_id, || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - sched_pusch->mcs = 9; + sched_pusch->mcs = nrmac->min_grant_mcs; update_ul_ue_R_Qm(sched_pusch, ps); sched_pusch->rbStart = rbStart; sched_pusch->rbSize = min_rb; @@ -1252,7 +1259,7 @@ void pf_ul(module_id_t module_id, add_tail_nr_list(&UE_sched, UE_id); /* Calculate coefficient*/ - sched_pusch->mcs = 9; + sched_pusch->mcs = nrmac->min_grant_mcs; const uint32_t tbs = ul_pf_tbs[ps->mcs_table][sched_pusch->mcs]; coeff_ue[UE_id] = (float) tbs / ul_thr_ue[UE_id]; LOG_D(NR_MAC,"b %d, ul_thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n", @@ -1401,7 +1408,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t if (tda < 0) return false; int K2 = get_K2(scc, sched_ctrl->active_ubwp, tda, mu); - const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); + const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu]))&1023; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 417318f8a3..d78fe4e154 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -806,6 +806,8 @@ typedef struct gNB_MAC_INST_s { double dl_rd2_bler_threshold; uint8_t dl_max_mcs; uint8_t harq_round_max; + uint8_t min_grant_prb; + uint8_t min_grant_mcs; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 5129d46ddc..1442a9af72 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -655,6 +655,7 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, if (entity->has_sdap == 1 && entity->has_sdapULheader == 1) offset = 1; // this is the offset of the SDAP header in bytes + message_p = itti_alloc_new_message_sized(TASK_PDCP_ENB, 0, GTPV1U_GNB_TUNNEL_DATA_REQ, sizeof(gtpv1u_gnb_tunnel_data_req_t) + size @@ -673,7 +674,10 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, LOG_I(PDCP, "%s() (drb %d) SDAP header %2x\n",__func__, rb_id, buf[0]); sdap_gnb_ul_header_handler(buf[0]); // Handler for the UL gNB SDAP Header } - LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size-offset); + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(PDCP, "%s() (drb %d) Time %lu.%lu sending message to gtp size %d\n", __func__, rb_id, time_request.tv_sec,time_request.tv_nsec, + size-offset); itti_send_msg_to_task(TASK_VARIABLE, INSTANCE_DEFAULT, message_p); } } @@ -725,7 +729,7 @@ rb_found: req->offset = GTPU_HEADER_OVERHEAD_MAX; req->rnti = ue->rnti; req->pdusession_id = rb_id; - LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", + LOG_I(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size); extern instance_t CUuniqInstance; itti_send_msg_to_task(TASK_VARIABLE, CUuniqInstance, message_p); @@ -733,8 +737,9 @@ rb_found: memblock = get_free_mem_block(size, __FUNCTION__); memcpy(memblock->data, buf, size); - - LOG_D(PDCP, "%s(): (srb %d) calling rlc_data_req size %d\n", __func__, rb_id, size); + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(PDCP, "%s(): (rb %d) calling enqueue_rlc_data_req size %d at time %lu.%lu\n", __func__, rb_id, size,time_request.tv_sec,time_request.tv_nsec); //for (i = 0; i < size; i++) printf(" %2.2x", (unsigned char)memblock->data[i]); //printf("\n"); enqueue_rlc_data_req(&ctxt, 0, MBMS_FLAG_NO, rb_id, sdu_id, 0, size, memblock); @@ -1342,7 +1347,9 @@ static boolean_t pdcp_data_req_drb( const sdu_size_t sdu_buffer_size, unsigned char *const sdu_buffer) { - LOG_D(PDCP, "%s() called, size %d\n", __func__, sdu_buffer_size); + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(PDCP, "%s() called at time %lu.%lu, size %d\n", __func__, time_request.tv_sec,time_request.tv_nsec,sdu_buffer_size); nr_pdcp_ue_t *ue; nr_pdcp_entity_t *rb; int rnti = ctxt_pP->rnti; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 78e06d37e2..b9d617d2eb 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -462,9 +462,14 @@ static void deliver_sdu(void *_ue, nr_rlc_entity_t *entity, char *buf, int size) exit(1); rb_found: - LOG_D(RLC, "%s:%d:%s: delivering SDU (rnti %d is_srb %d rb_id %d) size %d\n", - __FILE__, __LINE__, __FUNCTION__, ue->rnti, is_srb, rb_id, size); + if (is_srb==0) { + struct timespec time_request; + clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(RLC, "%s:%d:%s: delivering SDU Time %lu.%lu (rnti %d is_srb %d rb_id %d) size %d\n", + __FILE__, __LINE__, __FUNCTION__, time_request.tv_sec,time_request.tv_nsec, + ue->rnti, is_srb, rb_id, size); + } /* unused fields? */ ctx.instance = 0; ctx.frame = 0; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 65f835d3fd..4eb5b06585 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1051,7 +1051,7 @@ void fill_initial_SpCellConfig(rnti_t rnti, NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); pucchres0->pucch_ResourceId=0; //pucchres0->startingPRB=0; - pucchres0->startingPRB=(8+rnti) % curr_bwp; + pucchres0->startingPRB=(8+rnti) % (curr_bwp/2); LOG_D(NR_RRC, "pucchres0->startPRB %ld rnti %d curr_bwp %d\n", pucchres0->startingPRB, rnti, curr_bwp); pucchres0->intraSlotFrequencyHopping=NULL; pucchres0->secondHopPRB=NULL; @@ -1260,14 +1260,8 @@ void fill_initial_SpCellConfig(rnti_t rnti, schedulingRequestResourceConfig->schedulingRequestID= 0; schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40; - // note: make sure that there is no issue here. Later choose the RNTI accordingly. - // Here we would be limited to 3 UEs on this resource (1 1/2 Frames 30 kHz SCS, 5 ms TDD periodicity => slots 7,8,9). - // This should be a temporary resource until the first RRCReconfiguration gives new pucch resources. - // Check for above configuration and exit for now if it is not the case AssertFatal(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing==NR_SubcarrierSpacing_kHz30, "SCS != 30kHz\n"); - AssertFatal(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity==NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5, - "TDD period != 5ms : %ld\n",scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = 8; schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 6b7f9a21b9..af1fb92247 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -62,12 +62,30 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ //TODO change to accomodate for SRS - int temp_min_delay = 6; // k2 = 2 or 3 won'r work as well as higher values + lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + int temp_min_delay; + if(frame_type==TDD && scc->tdd_UL_DL_ConfigurationCommon) { + + switch (scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity) { + default: + temp_min_delay = 6; + break; + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms2p5: // 30kHz SCS + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms2: // 60kHz SCS + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms1p25: // 60kHz SCS + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms1: // 120kHz SCS + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms0p625: // 120kHz SCS + case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms0p5: // 120kHz SCS + temp_min_delay = 2; + break; + } + } + + int k2 = (min_fb_delayuplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; - lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation)); pusch_timedomainresourceallocation->k2 = CALLOC(1,sizeof(long)); @@ -77,6 +95,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ ASN_SEQUENCE_ADD(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation); if(frame_type==TDD) { + // TDD if(scc->tdd_UL_DL_ConfigurationCommon) { int ul_symb = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols; From 1976f433dcebbe7f7b2e9bfc6abd4bfab24f043b Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 22 Feb 2022 16:15:29 +0100 Subject: [PATCH 041/226] changes for Panther --- openair1/PHY/LTE_TRANSPORT/if5_tools.c | 32 ++++++++++++++---- targets/ARCH/AW2SORI/oaiori.c | 45 ++++++++++++++------------ 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index 9d53cafe71..e71b1e31f6 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -1106,9 +1106,9 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seq NR_DL_FRAME_PARMS *nrfp = ru->nr_frame_parms; - int offset,siglen; + int offset,siglen,factor=1; if (nrfp) { - offset = nrfp->get_samples_slot_timestamp(tti,nrfp,0); + offset = nrfp->get_samples_slot_timestamp(tti,nrfp,0); siglen = nrfp->get_samples_per_slot(tti,nrfp); } else { @@ -1116,6 +1116,13 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seq siglen = spsf; } + if (ru->openair0_cfg.nr_flag==1) { + if (nrfp->N_RB_DL <= 162 && nrfp->N_RB_DL >= 106) factor = 2; + else if (nrfp->N_RB_DL < 106) factor=4; + } + else { + factor = 30720/spsf; + } for (i=0; i < ru->nb_tx; i++) txp[i] = (int32_t*)&ru->common.txdata[i][offset]; @@ -1125,7 +1132,7 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seq //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 ); clock_gettime( CLOCK_MONOTONIC, &start_comp); ru->ifdevice.trx_write_func2(&ru->ifdevice, - (proc_timestamp + packet_id*spp_eth-600)*(30720/spsf), + (proc_timestamp + packet_id*spp_eth-600)*factor, (void*)txp[aid], spp_eth, aid, @@ -1326,6 +1333,8 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int tti, uint16_t pa NR_DL_FRAME_PARMS *nrfp = ru->nr_frame_parms; int offset,siglen; + int factor=1; + int ts_offset; if (nrfp) { offset = nrfp->get_samples_slot_timestamp(tti,nrfp,0); siglen = nrfp->get_samples_per_slot(tti,nrfp); @@ -1334,6 +1343,15 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int tti, uint16_t pa offset = tti*fp->samples_per_subframe; siglen = spsf; } + if (ru->openair0_cfg.nr_flag==1) { // This check if RRU knows about NR numerologies + if (nrfp->N_RB_DL <= 162 && nrfp->N_RB_DL >= 106) factor = 2; + else if (nrfp->N_RB_DL < 106) factor=4; + ts_offset = 64; + } + else { + factor = 30720/spsf; + ts_offset = 256; + } for (i=0; i < ru->nb_rx; i++) rxp[i] = &ru->common.rxdata[i][offset]; int aid; @@ -1352,12 +1370,12 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int tti, uint16_t pa &aid); clock_gettime( CLOCK_MONOTONIC, &if_time); timeout[packet_id] = if_time.tv_nsec; - timestamp[packet_id] /= (30720/spsf); - LOG_D(PHY,"TTI %d: Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",tti,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0])); + timestamp[packet_id] /= factor; // for LTE this is the sample rate reduction w.r.t 30.72, for NR 122.88 + LOG_D(PHY,"TTI %d: factor = %d Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",tti,factor,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0])); if (aid==0) { if (firstTS==1) firstTS=0; - else if (oldTS + 256 != timestamp[packet_id]) { + else if (oldTS + ts_offset != timestamp[packet_id]) { LOG_I(PHY,"oldTS %llu, newTS %llu, diff %llu, timein %lu, timeout %lu\n",(long long unsigned int)oldTS,(long long unsigned int)timestamp[packet_id],(long long unsigned int)timestamp[packet_id]-oldTS,timein[packet_id],timeout[packet_id]); for (int i=0;i<=packet_id;i++) LOG_I(PHY,"packet %d TS %llu, timein %lu, timeout %lu\n",i,(long long unsigned int)timestamp[i],timein[i],timeout[i]); AssertFatal(1==0,"fronthaul problem\n"); @@ -1369,7 +1387,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int tti, uint16_t pa // HYPOTHESIS: first packet per subframe has lowest timestamp of subframe // should detect out of order and act accordingly .... - AssertFatal(aid==0 || aid==1,"aid %d != 0 or 1\n",aid); + AssertFatal(aid==0 || aid==1 || aid==2 || aid==3,"aid %d != 0,1,2 or 3\n",aid); LOG_D(PHY,"rxp[%d] %p, dest %p, offset %d (%llu,%llu)\n",aid,rxp[aid],rxp[aid]+(timestamp[packet_id]-timestamp[0]),(int)(timestamp[packet_id]-timestamp[0]),(long long unsigned int)timestamp[packet_id],(long long unsigned int)timestamp[0]); memcpy((void*)(rxp[aid]+(timestamp[packet_id]-timestamp[0])), (void*)temp_rx, diff --git a/targets/ARCH/AW2SORI/oaiori.c b/targets/ARCH/AW2SORI/oaiori.c index 3872b05b3b..9cf15237cf 100644 --- a/targets/ARCH/AW2SORI/oaiori.c +++ b/targets/ARCH/AW2SORI/oaiori.c @@ -243,7 +243,7 @@ int aw2s_startstreaming(openair0_device *device) { tx1= (openair0_cfg->tx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 1, NULL) : NULL; tx2= (openair0_cfg->tx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 2, NULL) : NULL; tx3= (openair0_cfg->tx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_TxNRFDD : ORI_ObjectType_TxNRTDD, 3, NULL) : NULL; - rx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxEUtraFDD : ORI_ObjectType_RxEUtraTDD, 0, NULL); + rx0= ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 0, NULL); rx1= (openair0_cfg->rx_num_channels > 1) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 1, NULL) : NULL; rx2= (openair0_cfg->rx_num_channels > 2) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 2, NULL) : NULL; rx3= (openair0_cfg->rx_num_channels > 3) ? ORI_FindObject(ori, openair0_cfg->duplex_mode == duplex_mode_FDD ?ORI_ObjectType_RxNRFDD : ORI_ObjectType_RxNRTDD, 3, NULL) : NULL; @@ -259,8 +259,10 @@ int aw2s_startstreaming(openair0_device *device) { (rx1 == NULL && openair0_cfg->rx_num_channels > 1) || (rx2 == NULL && openair0_cfg->rx_num_channels > 2) || (rx3 == NULL && openair0_cfg->rx_num_channels > 3) || - link == NULL) return (-1); - + link == NULL) { + printf("tx0 %p, tx1 %p, tx2 %p, tx3 %p, rx0 %p, rx1 %p, rx2 %p, rx3 %p\n",tx0,tx1,tx2,tx3,rx0,rx1,rx2,rx3); + return (-1); + } /******************************************************************* * UNLOCK Link *******************************************************************/ @@ -415,7 +417,7 @@ int aw2s_startstreaming(openair0_device *device) { (openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) || tx0->fst != ORI_FST_Operational || (openair0_cfg->tx_num_channels > 1 && tx1->fst != ORI_FST_Operational)) - {} + {}*/ // test RX interface uint64_t TS; char temp_rx[1024] __attribute__((aligned(32))); @@ -604,7 +606,7 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx0, &RE_result); if(RE_result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (txParams0.TxEUtra/NRFDD/TDD) failed with error: %s (%s,%s,%s,%s,%s,%s\n", ORI_Result_Print(RE_result), + printf("ORI_ObjectCreation (txParams0.TxEUtra/NR/FDD/TDD) failed with error: %s (%s,%s,%s,%s,%s,%s\n", ORI_Result_Print(RE_result), ORI_Result_Print(txParamResult[0]), ORI_Result_Print(txParamResult[1]), ORI_Result_Print(txParamResult[2]), @@ -614,7 +616,7 @@ int aw2s_oriinit(openair0_device *device) { aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (txParams0.TxEUtra/NRFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (txParams0.TxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); /* Create tx1 */ @@ -631,11 +633,11 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx1, &RE_result); if(RE_result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (txParams1.TxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (txParams1.TxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); } if (openair0_cfg->tx_num_channels > 2) { @@ -651,11 +653,11 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx2, &RE_result); if(RE_result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (txParams1.TxEUtraFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (txParams2.TxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (txParams1.TxEUtraFDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (txParams2.TxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); } if (openair0_cfg->tx_num_channels == 4) { ORI_Object_s * tx3; @@ -670,7 +672,7 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectCreation(ori, txTypeRef, txParams, txParamList, num_txparams, txParamResult, &tx3, &RE_result); if(RE_result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (txParams1.TxEUtra/NRFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (txParams3.TxEUtra/NRFDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } @@ -688,7 +690,8 @@ int aw2s_oriinit(openair0_device *device) { (openair0_cfg->nr_flag == 0 ? ORI_ObjectType_RxEUtraTDD : ORI_ObjectType_RxNRTDD)}; ORI_ObjectParams_u rxParams; ORI_ObjectParam_e rxParamList[5] = { ORI_ObjectParam_SigPath_antPort, ORI_ObjectParam_SigPath_axcW, ORI_ObjectParam_SigPath_axcB, - ORI_ObjectParam_SigPath_chanBW, ORI_ObjectParam_SigPath_earfcn }; + ORI_ObjectParam_SigPath_chanBW, + openair0_cfg->nr_flag == 0 ? ORI_ObjectParam_SigPath_earfcn : ORI_ObjectParam_SigPath_AWS_arfcn}; ORI_Result_e rxParamResult[5]; int num_rxparams = 5; /* Create rx0 */ @@ -783,11 +786,11 @@ int aw2s_oriinit(openair0_device *device) { if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (rxParams2.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (rxParams2.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); } if (openair0_cfg->rx_num_channels > 3) { /* Create rx3 */ @@ -806,11 +809,11 @@ int aw2s_oriinit(openair0_device *device) { if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectCreation (rxParams3.RxEUtra/NR/FDD/TDD) failed with error: %s\n", ORI_Result_Print(result)); aw2s_oricleanup(device); return -1; } - printf("ORI_ObjectCreation (rxParams1.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); + printf("ORI_ObjectCreation (rxParams3.RxEUtra/NR/FDD/TDD): %s\n", ORI_Result_Print(RE_result)); } /* Create link */ @@ -827,14 +830,14 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectParamModify(ori,link,linkParams,linkParamList,3,linkParamResult,&RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectParamModify (linkParams) failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectParamModify (linkParams) failed with error: %s\n", ORI_Result_Print(RE_result)); aw2s_oricleanup(device); return -1; } result = ORI_ObjectStateModification(ori, link, ORI_AST_Locked, &RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(RE_result)); aw2s_oricleanup(device); return -1; } @@ -850,7 +853,7 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectParamReport(ori, NULL, 0, ORI_ObjectParam_All, &RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectParamReport failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectParamReport failed with error: %s\n", ORI_Result_Print(RE_result)); aw2s_oricleanup(device); return -1; } @@ -869,7 +872,7 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectStateReport(ori, NULL, 0, ORI_StateType_All, ORI_EventDrivenReport_True, &RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectStateReport failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectStateReport failed with error: %s\n", ORI_Result_Print(RE_result)); aw2s_oricleanup(device); return -1; } @@ -893,7 +896,7 @@ int aw2s_oriinit(openair0_device *device) { result = ORI_ObjectFaultReport(ori, NULL, 0, ORI_EventDrivenReport_True, &RE_result); if(result != ORI_Result_SUCCESS) { - printf("ORI_ObjectFaultReport failed with error: %s\n", ORI_Result_Print(result)); + printf("ORI_ObjectFaultReport failed with error: %s\n", ORI_Result_Print(RE_result)); aw2s_oricleanup(device); return -1; } From 7bda635e03ec8b73ca65dd6b21e285bdf952494b Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 1 Mar 2022 10:57:54 +0100 Subject: [PATCH 042/226] handling 2-port CSI report at MAC gNB --- openair1/PHY/INIT/nr_init.c | 8 +++---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 12 ++++++++++ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 24 +++++++++++++++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 8 ++++++- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 5 ++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 ++++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index ee9079fd57..3a6151183f 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -136,7 +136,7 @@ int init_codebook_gNB(PHY_VARS_gNB *gNB) { } } - int max_mimo_layers =(CSI_RS_antenna_portsnr_mimo_precoding_matrix = (int32_t ***)malloc16(max_mimo_layers* sizeof(int32_t **)); int32_t ***mat = gNB->nr_mimo_precoding_matrix; @@ -236,7 +236,7 @@ int init_codebook_gNB(PHY_VARS_gNB *gNB) { if((llb != ll) || (mmb != mm) || ((N1 == 1) && (N2 == 1))){ pmiq += 1; mat[1][pmiq] = (int32_t *)malloc16((2*N1*N2)*(2)*sizeof(int32_t)); - LOG_I(PHY, "layer 2 Codebook pmiq = %d\n",pmiq); + LOG_D(PHY, "layer 2 Codebook pmiq = %d\n",pmiq); for(int j_col=0; j_col<2; j_col++) { if (j_col==0) { llc = llb; @@ -320,7 +320,7 @@ int init_codebook_gNB(PHY_VARS_gNB *gNB) { if((llb != ll) || (mmb != mm)){ pmiq += 1; mat[2][pmiq] = (int32_t *)malloc16((2*N1*N2)*(3)*sizeof(int32_t)); - LOG_I(PHY, "layer 3 Codebook pmiq = %d\n",pmiq); + LOG_D(PHY, "layer 3 Codebook pmiq = %d\n",pmiq); for(int j_col=0; j_col<3; j_col++) { if (j_col==0) { llc = llb; @@ -411,7 +411,7 @@ int init_codebook_gNB(PHY_VARS_gNB *gNB) { if((llb != ll) || (mmb != mm)){ pmiq += 1; mat[3][pmiq] = (int32_t *)malloc16((2*N1*N2)*4*sizeof(int32_t)); - LOG_I(PHY, "layer 4 pmiq = %d\n",pmiq); + LOG_D(PHY, "layer 4 pmiq = %d\n",pmiq); for(int j_col=0; j_col<4; j_col++) { if (j_col==0) { llc = llb; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 92391ed1d5..6fa460026b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1174,6 +1174,18 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->StartSymbolIndex = ps->startSymbolIndex; pdsch_pdu->NrOfSymbols = ps->nrOfSymbols; + // Precoding + if (sched_ctrl->set_pmi) { + int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id; + nr_csi_report_t *csi_report = &UE_info->csi_report_template[UE_id][report_id]; + pdsch_pdu->precodingAndBeamforming.prg_size = pdsch_pdu->rbSize; + pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = set_pm_index(sched_ctrl, + nrOfLayers, + csi_report->N1, + csi_report->N2, + csi_report->codebook_mode); + } + NR_PDSCH_Config_t *pdsch_Config=NULL; if (bwp && bwp->bwp_Dedicated && diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 721f67295b..59a8811cfc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -145,6 +145,25 @@ uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl) { } + +uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, + int layers, + int N1, int N2, + int codebook_mode) { + + int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1; + int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2; + int antenna_ports = (N1*N2)<<1; + + sched_ctrl->set_pmi = false; + + if (antenna_ports == 2) + return x2; + else + AssertFatal(1==0,"More than 2 antenna ports not yet supported\n"); +} + + void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, NR_UE_sched_ctrl_t *sched_ctrl, uint8_t *target_mcs, @@ -186,7 +205,7 @@ void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, } } } - sched_ctrl->set_mcs = FALSE; + sched_ctrl->set_mcs = false; } } @@ -2147,7 +2166,8 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, mod_idP); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); - sched_ctrl->set_mcs = TRUE; + sched_ctrl->set_mcs = true; + sched_ctrl->set_pmi = false; sched_ctrl->lcid_mask = 0; if (!get_softmodem_params()->phy_test && !get_softmodem_params()->do_ra && !get_softmodem_params()->sa) { sched_ctrl->lcid_mask = 1<codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.moreThanTwo); get_x1x2_bitlen_singlepanel(n1,n2,o1,o2,&x1,&x2,i+1,codebookConfig->codebookType.choice.type1->codebookMode); + csi_report->N1 = n1; + csi_report->N2 = n2; + csi_report->codebook_mode = codebookConfig->codebookType.choice.type1->codebookMode; csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=x1; csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=x2; } @@ -1210,7 +1213,7 @@ void evaluate_cqi_report(uint8_t *payload, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_2tb = temp_cqi; LOG_D(MAC,"Wide-band CQI for the second TB %d\n", temp_cqi); } - sched_ctrl->set_mcs = TRUE; + sched_ctrl->set_mcs = true; } @@ -1233,6 +1236,7 @@ uint8_t evaluate_pmi_report(uint8_t *payload, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); + sched_ctrl->set_pmi = true; return tot_bitlen; } @@ -1338,6 +1342,7 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, if (r_index != -1) skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; cumul_bits += pmi_bitlen; evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl,csirep->cqi_Table); break; @@ -1355,6 +1360,7 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, if (r_index != -1) skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; cumul_bits += pmi_bitlen; evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl,csirep->cqi_Table); break; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index fcc020ee83..1319aa6a83 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -455,6 +455,11 @@ void find_SSB_and_RO_available(module_id_t module_idP); void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps); +uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, + int layers, + int N1, int N2, + int codebook_mode); + void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, NR_UE_sched_ctrl_t *sched_ctrl, uint8_t *target_mcs, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 22a0932c3f..68f6455f89 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -479,6 +479,7 @@ struct CRI_RI_LI_PMI_CQI { uint8_t wb_cqi_1tb; uint8_t wb_cqi_2tb; uint8_t cqi_table; + uint8_t csi_report_id; }; typedef struct CRI_SSB_RSRP { @@ -522,6 +523,9 @@ typedef struct nr_csi_report { uint8_t nb_of_csi_ssb_report; L1_RSRP_bitlen_t CSI_report_bitlen; CSI_Meas_bitlen_t csi_meas_bitlen; + int codebook_mode; + int N1; + int N2; } nr_csi_report_t; /*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report @@ -621,6 +625,7 @@ typedef struct { struct CSI_Report CSI_report; bool SR; bool set_mcs; + bool set_pmi; /// information about every HARQ process NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; /// HARQ processes that are free From 79a5249a725bec9f251e5f676436e4a4e945f270 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 5 Mar 2022 16:18:06 +0100 Subject: [PATCH 043/226] for testing --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index a48a59b67b..4c902e2675 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -979,6 +979,9 @@ void nr_schedule_ue_spec(module_id_t module_id, gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; if (!is_xlsch_in_slot(gNB_mac->dlsch_slot_bitmap[slot / 64], slot)) return; + + //if (slot==7 || slot == 17) return; + /* PREPROCESSOR */ gNB_mac->pre_processor_dl(module_id, frame, slot); From 4ca985858ffaf42bbb000da04a4a002d48c13f5d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 5 Mar 2022 22:24:34 +0100 Subject: [PATCH 044/226] to trigger CI --- targets/ARCH/AW2SORI/oaiori.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ARCH/AW2SORI/oaiori.c b/targets/ARCH/AW2SORI/oaiori.c index fc35e021b8..3c424086dd 100644 --- a/targets/ARCH/AW2SORI/oaiori.c +++ b/targets/ARCH/AW2SORI/oaiori.c @@ -417,7 +417,7 @@ int aw2s_startstreaming(openair0_device *device) { (openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) || tx0->fst != ORI_FST_Operational || (openair0_cfg->tx_num_channels > 1 && tx1->fst != ORI_FST_Operational)) - {}*/ + {}*/ // test RX interface uint64_t TS; char temp_rx[2048] __attribute__((aligned(32))); From 091386174e476a224ebcaeddb0bfbf2f346ea12f Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 5 Mar 2022 23:20:35 +0100 Subject: [PATCH 045/226] bugfix for new sf_ahead parameter --- targets/RT/USER/lte-ru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 16f26cc95c..8a5ae99f19 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -3070,7 +3070,7 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); - ru[j]->sf_ahead = *(RUParamList.paramarray[j][RU_SF_AHEAD_IDX].uptr); + ru[j]->sf_ahead = *(RUParamList.paramarray[j][RU_SF_AHEAD].uptr); *ru_mask= (*ru_mask)|(1< Date: Sun, 6 Mar 2022 09:40:36 +0100 Subject: [PATCH 046/226] build for NR UE --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 56 ++++++++++++++++++++ openair2/RRC/NR/nr_rrc_proto.h | 1 + openair2/RRC/NR/rrc_gNB_reconfig.c | 55 ------------------- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 4 +- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 665e27f7b7..d3e4b615a4 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1004,6 +1004,62 @@ long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { return c_srs; } +void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, + NR_CSI_MeasConfig_t *csi_MeasConfig, + int dl_antenna_ports, + int curr_bwp, + int do_csirs) { + + if (do_csirs) { + csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList = calloc(1,sizeof(*csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList)); + NR_NZP_CSI_RS_Resource_t *nzpcsi0 = calloc(1,sizeof(*nzpcsi0)); + nzpcsi0->nzp_CSI_RS_ResourceId = 0; + NR_CSI_RS_ResourceMapping_t resourceMapping; + switch (dl_antenna_ports) { + case 1: + resourceMapping.frequencyDomainAllocation.present = NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2; + resourceMapping.frequencyDomainAllocation.choice.row2.buf = calloc(2, sizeof(uint8_t)); + resourceMapping.frequencyDomainAllocation.choice.row2.size = 2; + resourceMapping.frequencyDomainAllocation.choice.row2.bits_unused = 4; + resourceMapping.frequencyDomainAllocation.choice.row2.buf[0] = 0; + resourceMapping.frequencyDomainAllocation.choice.row2.buf[1] = 16; + resourceMapping.nrofPorts = NR_CSI_RS_ResourceMapping__nrofPorts_p1; + resourceMapping.cdm_Type = NR_CSI_RS_ResourceMapping__cdm_Type_noCDM; + break; + case 2: + resourceMapping.frequencyDomainAllocation.present = NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other; + resourceMapping.frequencyDomainAllocation.choice.other.buf = calloc(2, sizeof(uint8_t)); + resourceMapping.frequencyDomainAllocation.choice.other.size = 1; + resourceMapping.frequencyDomainAllocation.choice.other.bits_unused = 2; + resourceMapping.frequencyDomainAllocation.choice.other.buf[0] = 4; + resourceMapping.nrofPorts = NR_CSI_RS_ResourceMapping__nrofPorts_p2; + resourceMapping.cdm_Type = NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2; + break; + default: + AssertFatal(1==0,"Number of ports not yet supported\n"); + } + resourceMapping.firstOFDMSymbolInTimeDomain = 6; + resourceMapping.firstOFDMSymbolInTimeDomain2 = NULL; + resourceMapping.density.present = NR_CSI_RS_ResourceMapping__density_PR_one; + resourceMapping.density.choice.one = (NULL_t)0; + resourceMapping.freqBand.startingRB = 0; + resourceMapping.freqBand.nrofRBs = ((curr_bwp>>2)+(curr_bwp%4>0))<<2; + nzpcsi0->resourceMapping = resourceMapping; + nzpcsi0->powerControlOffset = 0; + nzpcsi0->powerControlOffsetSS=calloc(1,sizeof(*nzpcsi0->powerControlOffsetSS)); + *nzpcsi0->powerControlOffsetSS = NR_NZP_CSI_RS_Resource__powerControlOffsetSS_db0; + nzpcsi0->scramblingID = *servingcellconfigcommon->physCellId; + nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset)); + nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; + nzpcsi0->periodicityAndOffset->choice.slots320 = 0; + nzpcsi0->qcl_InfoPeriodicCSI_RS = calloc(1,sizeof(*nzpcsi0->qcl_InfoPeriodicCSI_RS)); + *nzpcsi0->qcl_InfoPeriodicCSI_RS=0; + ASN_SEQUENCE_ADD(&csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list,nzpcsi0); + } + else + csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList = NULL; +} + void fill_initial_SpCellConfig(int uid, NR_SpCellConfig_t *SpCellConfig, NR_ServingCellConfigCommon_t *scc, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 205267e288..08c6709497 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -84,6 +84,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco int do_srs, int uid); + void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int dl_antenna_ports, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 120a508cdf..7c733a19e6 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -1318,61 +1318,6 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco } -void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, - NR_CSI_MeasConfig_t *csi_MeasConfig, - int dl_antenna_ports, - int curr_bwp, - int do_csirs) { - - if (do_csirs) { - csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList = calloc(1,sizeof(*csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList)); - NR_NZP_CSI_RS_Resource_t *nzpcsi0 = calloc(1,sizeof(*nzpcsi0)); - nzpcsi0->nzp_CSI_RS_ResourceId = 0; - NR_CSI_RS_ResourceMapping_t resourceMapping; - switch (dl_antenna_ports) { - case 1: - resourceMapping.frequencyDomainAllocation.present = NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2; - resourceMapping.frequencyDomainAllocation.choice.row2.buf = calloc(2, sizeof(uint8_t)); - resourceMapping.frequencyDomainAllocation.choice.row2.size = 2; - resourceMapping.frequencyDomainAllocation.choice.row2.bits_unused = 4; - resourceMapping.frequencyDomainAllocation.choice.row2.buf[0] = 0; - resourceMapping.frequencyDomainAllocation.choice.row2.buf[1] = 16; - resourceMapping.nrofPorts = NR_CSI_RS_ResourceMapping__nrofPorts_p1; - resourceMapping.cdm_Type = NR_CSI_RS_ResourceMapping__cdm_Type_noCDM; - break; - case 2: - resourceMapping.frequencyDomainAllocation.present = NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other; - resourceMapping.frequencyDomainAllocation.choice.other.buf = calloc(2, sizeof(uint8_t)); - resourceMapping.frequencyDomainAllocation.choice.other.size = 1; - resourceMapping.frequencyDomainAllocation.choice.other.bits_unused = 2; - resourceMapping.frequencyDomainAllocation.choice.other.buf[0] = 4; - resourceMapping.nrofPorts = NR_CSI_RS_ResourceMapping__nrofPorts_p2; - resourceMapping.cdm_Type = NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2; - break; - default: - AssertFatal(1==0,"Number of ports not yet supported\n"); - } - resourceMapping.firstOFDMSymbolInTimeDomain = 6; - resourceMapping.firstOFDMSymbolInTimeDomain2 = NULL; - resourceMapping.density.present = NR_CSI_RS_ResourceMapping__density_PR_one; - resourceMapping.density.choice.one = (NULL_t)0; - resourceMapping.freqBand.startingRB = 0; - resourceMapping.freqBand.nrofRBs = ((curr_bwp>>2)+(curr_bwp%4>0))<<2; - nzpcsi0->resourceMapping = resourceMapping; - nzpcsi0->powerControlOffset = 0; - nzpcsi0->powerControlOffsetSS=calloc(1,sizeof(*nzpcsi0->powerControlOffsetSS)); - *nzpcsi0->powerControlOffsetSS = NR_NZP_CSI_RS_Resource__powerControlOffsetSS_db0; - nzpcsi0->scramblingID = *servingcellconfigcommon->physCellId; - nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset)); - nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; - nzpcsi0->periodicityAndOffset->choice.slots320 = 0; - nzpcsi0->qcl_InfoPeriodicCSI_RS = calloc(1,sizeof(*nzpcsi0->qcl_InfoPeriodicCSI_RS)); - *nzpcsi0->qcl_InfoPeriodicCSI_RS=0; - ASN_SEQUENCE_ADD(&csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list,nzpcsi0); - } - else - csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList = NULL; -} void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon, diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 5da5cd0b67..0533f2f100 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -673,7 +673,7 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp if (samples_received == nsamps) s->wait_for_first_pps=0; // bring RX data into 12 LSBs for softmodem RX - for (int i=0; itype==USRP_X300_DEV) { openair0_cfg[0].rx_gain_calib_table = calib_table_x310; std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; - // s->usrp->set_rx_dc_offset(true); } if (device->type==USRP_N300_DEV) { From fcd88de2ab2fe1b640ce5eb1f4070fb5fe57ceaa Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 7 Mar 2022 00:08:12 +0100 Subject: [PATCH 047/226] SR/CSI multiplexing fix. default sl_head=6 instead of 4 to check if RF simulator behaves better --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + openair2/ENB_APP/enb_paramdef.h | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 5 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 49 +++++++++++++++++-- openair2/RRC/NR/MESSAGES/asn1_msg.c | 6 +-- 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 283ff1934c..db36b39f99 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -104,6 +104,8 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, pucch->frame = frame; pucch->slot = slot; pucch->active = 1; + if (pucch->pucch_pdu.format_type > 0) LOG_D(PHY,"Programming PUCCH[%d] for %d.%d, format %d, nb_harq %d, nb_sr %d, nb_csi %d\n",id, + pucch->frame,pucch->slot,pucch->pucch_pdu.format_type,pucch->pucch_pdu.bit_len_harq,pucch->pucch_pdu.sr_flag,pucch->pucch_pdu.bit_len_csi_part1); memcpy((void*)&pucch->pucch_pdu, (void*)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t)); } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 6ba673dbc7..435b633c3b 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -699,6 +699,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->uci_pdu_list[num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu_format2 = &gNB->uci_pdu_list[num_ucis].pucch_pdu_format_2_3_4; + LOG_D(PHY,"%d.%d Calling nr_decode_pucch2\n",frame_rx,slot_rx); nr_decode_pucch2(gNB, slot_rx, uci_pdu_format2, diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index a533b8cb23..21e2e1b703 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -172,7 +172,7 @@ typedef enum { {CONFIG_STRING_RU_IF_FREQ_OFFSET, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_DO_PRECODING, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_SF_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ - {CONFIG_STRING_RU_SL_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_SL_AHEAD, NULL, 0, iptr:NULL, defintval:6, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_FLAG, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 51541353f4..e97e75ea16 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -368,8 +368,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, schedule_nr_prach(module_idP, f, s); } - // This schedule SR - nr_sr_reporting(module_idP, frame, slot); // Schedule CSI-RS transmission nr_csirs_scheduling(module_idP, frame, slot, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]); @@ -398,6 +396,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, nr_schedule_pucch(module_idP, frame, slot); + // This schedule SR after PUCCH for multiplexing + nr_sr_reporting(module_idP, frame, slot); + stop_meas(&RC.nrmac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 3203b536f6..886b675e41 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1225,6 +1225,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, } } AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id); + LOG_D(NR_MAC,"Configure pucch: pucch_pdu->format_type %d pucch_pdu->bit_len_harq %d, pucch->pdu->bit_len_csi %d\n",pucch_pdu->format_type,pucch_pdu->bit_len_harq,pucch_pdu->bit_len_csi_part1); } else { // this is the default PUCCH configuration, PUCCH format 0 or 1 LOG_D(NR_MAC,"pucch_acknak: Filling default PUCCH configuration from Tables (r_pucch %d, bwp %p)\n",r_pucch,bwp); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 8ca409695e..3688ac7771 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -153,7 +153,8 @@ void nr_schedule_pucch(int Mod_idP, || frameP != curr_pucch->frame || slotP != curr_pucch->ul_slot) continue; - LOG_D(NR_MAC,"Scheduling PUCCH[%d] RX for UE %d in %d.%d O_ack %d\n",i,UE_id,curr_pucch->frame,curr_pucch->ul_slot,O_ack); + if (O_csi > 0) LOG_D(NR_MAC,"Scheduling PUCCH[%d] RX for UE %d in %d.%d O_ack %d, O_sr %d, O_csi %d\n", + i,UE_id,curr_pucch->frame,curr_pucch->ul_slot,O_ack,O_sr,O_csi); nr_fill_nfapi_pucch(Mod_idP, frameP, slotP, curr_pucch, UE_id); memset(curr_pucch, 0, sizeof(*curr_pucch)); } @@ -773,6 +774,7 @@ void nr_csi_meas_reporting(int Mod_idP, len = pucchres->format.choice.format2->nrofPRBs; mask = ((1 << pucchres->format.choice.format2->nrofSymbols) - 1) << pucchres->format.choice.format2->startingSymbolIndex; curr_pucch->simultaneous_harqcsi = pucch_Config->format2->choice.setup->simultaneousHARQ_ACK_CSI; + LOG_D(NR_MAC,"%d.%d Allocating PUCCH format 2, startPRB %d, nPRB %d, simulHARQ %d, num_bits %d\n", frame, sched_slot,start,len,curr_pucch->simultaneous_harqcsi,curr_pucch->csi_bits); break; case NR_PUCCH_Resource__format_PR_format3: len = pucchres->format.choice.format3->nrofPRBs; @@ -1171,9 +1173,6 @@ void evaluate_rsrp_report(NR_UE_info_t *UE_info, // including ssb rsrp in mac stats stats->cumul_rsrp += strongest_ssb_rsrp; stats->num_rsrp_meas++; - LOG_D(MAC,"rsrp_id = %d rsrp = %d\n", - sched_ctrl->CSI_report.ssb_cri_report.RSRP, - get_measured_rsrp(sched_ctrl->CSI_report.ssb_cri_report.RSRP)); } @@ -1888,11 +1887,51 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) && pdu->initial_cyclic_shift == pucch_res->format.choice.format0->initialCyclicShift && pdu->nr_of_symbols == pucch_res->format.choice.format0->nrofSymbols && pdu->start_symbol_index == pucch_res->format.choice.format0->startingSymbolIndex) { - LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH format 0 nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); pdu->sr_flag = 1; nfapi_allocated = true; break; } + else if (pdu->rnti == UE_info->rnti[UE_id] + && pdu->format_type == 2 // does not use NR_PUCCH_Resource__format_PR_format0 + && pdu->nr_of_symbols == pucch_res->format.choice.format2->nrofSymbols + && pdu->start_symbol_index == pucch_res->format.choice.format2->startingSymbolIndex) { + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH format 2 nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + pdu->sr_flag = 1; + nfapi_allocated = true; + break; + + } + else if (pdu->rnti == UE_info->rnti[UE_id] + && pdu->format_type == 1 // does not use NR_PUCCH_Resource__format_PR_format0 + && pdu->nr_of_symbols == pucch_res->format.choice.format1->nrofSymbols + && pdu->start_symbol_index == pucch_res->format.choice.format1->startingSymbolIndex) { + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH format 1 nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + pdu->sr_flag = 1; + nfapi_allocated = true; + break; + + } + else if (pdu->rnti == UE_info->rnti[UE_id] + && pdu->format_type == 3 // does not use NR_PUCCH_Resource__format_PR_format0 + && pdu->nr_of_symbols == pucch_res->format.choice.format3->nrofSymbols + && pdu->start_symbol_index == pucch_res->format.choice.format3->startingSymbolIndex) { + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH format 3 nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + pdu->sr_flag = 1; + nfapi_allocated = true; + break; + + } + else if (pdu->rnti == UE_info->rnti[UE_id] + && pdu->format_type == 4 // does not use NR_PUCCH_Resource__format_PR_format0 + && pdu->nr_of_symbols == pucch_res->format.choice.format4->nrofSymbols + && pdu->start_symbol_index == pucch_res->format.choice.format4->startingSymbolIndex) { + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH format 4 nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + pdu->sr_flag = 1; + nfapi_allocated = true; + break; + + } } if (nfapi_allocated) // break scheduling resource loop, continue next UE diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index d3e4b615a4..f5d6b228f9 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1051,7 +1051,7 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, nzpcsi0->scramblingID = *servingcellconfigcommon->physCellId; nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset)); nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; - nzpcsi0->periodicityAndOffset->choice.slots320 = 0; + nzpcsi0->periodicityAndOffset->choice.slots320 = 20; nzpcsi0->qcl_InfoPeriodicCSI_RS = calloc(1,sizeof(*nzpcsi0->qcl_InfoPeriodicCSI_RS)); *nzpcsi0->qcl_InfoPeriodicCSI_RS=0; ASN_SEQUENCE_ADD(&csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list,nzpcsi0); @@ -1596,7 +1596,7 @@ void fill_initial_SpCellConfig(int uid, csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic)); csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 8 + (20 * uid) % 320; + csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (8 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep1->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep1->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI; csirep1->reportQuantity.choice.cri_RI_PMI_CQI=(NULL_t)0; @@ -1655,7 +1655,7 @@ void fill_initial_SpCellConfig(int uid, csirep2->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep2->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep2->reportConfigType.choice.periodic)); csirep2->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 28 + (20 * uid) % 320; + csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (28 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep2->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep2->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep2->reportQuantity.choice.cri_RSRP=(NULL_t)0; From f2e21b73812fe7a453807b9a696f044c5394ef1f Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 8 Mar 2022 07:47:46 +0100 Subject: [PATCH 048/226] removed AssertFatal in nr_sch_dmrs.c which prevented using type B configuration (e.g. for 10 MHz test in CI) --- openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c index 159f1172f8..a62138621d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c @@ -92,6 +92,5 @@ uint8_t get_l0(uint16_t dlDmrsSymbPos) { if ((mask&1) == 1) break; mask>>=1; } - AssertFatal(l0 < 4,"impossible l0 %d, dlDmrsSymbPos %x\n",l0,dlDmrsSymbPos); return (l0); } From 06d488bb23ac6d17e72eda8fa0a6a5f75fdb2644 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 9 Mar 2022 17:35:38 +0100 Subject: [PATCH 049/226] ulsch memory optimization --- openair1/PHY/INIT/nr_init_ue.c | 4 +- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 26 ++++++---- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 6 ++- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 4 +- .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 47 ++++++++++++------- openair1/PHY/defs_gNB.h | 10 ++-- openair1/PHY/defs_nr_common.h | 3 +- openair1/SIMULATION/NR_PHY/ulschsim.c | 4 +- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 2 +- 9 files changed, 61 insertions(+), 45 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 6626d4614c..5a26bfcfac 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -684,7 +684,7 @@ void term_nr_ue_transport(PHY_VARS_NR_UE *ue) for (int j = 0; j < 2; j++) { for (int k = 0; k < RX_NB_TH_MAX; k++) { free_nr_ue_dlsch(&ue->dlsch[k][i][j], N_RB_DL); - free_nr_ue_ulsch(&ue->ulsch[k][i][j], N_RB_DL); + free_nr_ue_ulsch(&ue->ulsch[k][i][j], N_RB_DL, &ue->frame_parms); } } @@ -702,7 +702,7 @@ void init_nr_ue_transport(PHY_VARS_NR_UE *ue) for (int k=0; kdlsch[k][i][j] = new_nr_ue_dlsch(1,NR_MAX_DLSCH_HARQ_PROCESSES,NSOFT,MAX_LDPC_ITERATIONS,ue->frame_parms.N_RB_DL))!=NULL,"Can't get ue dlsch structures\n"); LOG_D(PHY,"dlsch[%d][%d][%d] => %p\n",k,i,j,ue->dlsch[k][i][j]); - AssertFatal((ue->ulsch[k][i][j] = new_nr_ue_ulsch(ue->frame_parms.N_RB_UL, NR_MAX_ULSCH_HARQ_PROCESSES))!=NULL,"Can't get ue ulsch structures\n"); + AssertFatal((ue->ulsch[k][i][j] = new_nr_ue_ulsch(ue->frame_parms.N_RB_UL, NR_MAX_ULSCH_HARQ_PROCESSES,&ue->frame_parms))!=NULL,"Can't get ue ulsch structures\n"); LOG_D(PHY,"ulsch[%d][%d][%d] => %p\n",k,i,j,ue->ulsch[k][i][j]); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 304dad96f0..4a824dc678 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -57,8 +57,7 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulschptr, uint16_t N_RB_UL) { - int i,r; - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS; //number of segments to be allocated + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated NR_gNB_ULSCH_t *ulsch = *ulschptr; if (N_RB_UL != 273) { @@ -66,19 +65,21 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulschptr, uint16_t N_RB_UL) a_segments = a_segments/273 +1; } - for (i=0; iharq_processes[i]) { if (ulsch->harq_processes[i]->b) { free_and_zero(ulsch->harq_processes[i]->b); ulsch->harq_processes[i]->b = NULL; } - for (r=0; rharq_processes[i]->c[r]); free_and_zero(ulsch->harq_processes[i]->d[r]); - free_and_zero(ulsch->harq_processes[i]->w[r]); nrLDPC_free_mem(ulsch->harq_processes[i]->p_nrLDPC_procBuf[r]); ulsch->harq_processes[i]->p_nrLDPC_procBuf[r] = NULL; } + free_and_zero(ulsch->harq_processes[i]->c); + free_and_zero(ulsch->harq_processes[i]->d); + free_and_zero(ulsch->harq_processes[i]->p_nrLDPC_procBuf); free_and_zero(ulsch->harq_processes[i]); ulsch->harq_processes[i] = NULL; } @@ -92,7 +93,7 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL) NR_gNB_ULSCH_t *ulsch; uint8_t i,r; - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS; //number of segments to be allocated + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated if (N_RB_UL != 273) { a_segments = a_segments*N_RB_UL; @@ -109,11 +110,13 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL) ulsch->harq_processes[i] = (NR_UL_gNB_HARQ_t *)malloc16_clear(sizeof(NR_UL_gNB_HARQ_t)); ulsch->harq_processes[i]->b = (uint8_t*)malloc16_clear(ulsch_bytes); + ulsch->harq_processes[i]->c = (uint8_t**)malloc16_clear(a_segments); + ulsch->harq_processes[i]->d = (int16_t**)malloc16_clear(a_segments); + ulsch->harq_processes[i]->p_nrLDPC_procBuf = (t_nrLDPC_procBuf **)malloc16_clear(a_segments); for (r=0; rharq_processes[i]->p_nrLDPC_procBuf[r] = nrLDPC_init_mem(); ulsch->harq_processes[i]->c[r] = (uint8_t*)malloc16_clear(8448*sizeof(uint8_t)); ulsch->harq_processes[i]->d[r] = (int16_t*)malloc16_clear((68*384)*sizeof(int16_t)); - ulsch->harq_processes[i]->w[r] = (int16_t*)malloc16_clear((3*(6144+64))*sizeof(int16_t)); } } @@ -265,9 +268,12 @@ void nr_processULSegment(void* arg) { //////////////////////////// ulsch_llr =====> ulsch_harq->e ////////////////////////////// + /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t harq_e[3*8448]; + nr_deinterleaving_ldpc(E, Qm, - ulsch_harq->e[r], + harq_e, ulsch_llr+r_offset); //for (int i =0; i<16; i++) @@ -292,7 +298,7 @@ void nr_processULSegment(void* arg) { p_decoderParms->BG, p_decoderParms->Z, ulsch_harq->d[r], - ulsch_harq->e[r], + harq_e, ulsch_harq->C, rv_index, ulsch_harq->new_rx, @@ -539,7 +545,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, r_offset = 0; - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS; //number of segments to be allocated + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*n_layers; //number of segments to be allocated if (nb_rb != 273) { a_segments = a_segments*nb_rb; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 9bc3643557..822edcc3d9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -63,10 +63,12 @@ void free_nr_ue_dlsch(NR_UE_DLSCH_t **dlsch, uint16_t N_RB_DL); */ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_turbo_iterations,uint16_t N_RB_DL); +void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, + uint16_t N_RB_UL, + NR_DL_FRAME_PARMS* frame_parms); -void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulsch, uint16_t N_RB_UL); -NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids); +NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, NR_DL_FRAME_PARMS* frame_parms); /** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/QPSK reception. @param stream0_in Input from channel compensated (MR combined) stream 0 diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index caf3a19d85..9d5beb9d20 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -84,9 +84,9 @@ typedef struct { /// Pointer to the payload + CRC uint8_t *b; /// Pointers to transport block segments - uint8_t *c[MAX_NUM_NR_ULSCH_SEGMENTS]; + uint8_t **c; /// LDPC-code outputs - uint8_t *d[MAX_NUM_NR_ULSCH_SEGMENTS]; + uint8_t **d; /// LDPC-code outputs (TS 36.212 V15.4.0, Sec 5.3.2 p. 17) uint8_t *e; /// Rate matching (Interleaving) outputs (TS 36.212 V15.4.0, Sec 5.4.2.2 p. 30) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 5160a643fb..b1966aaa43 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -43,10 +43,10 @@ //#define DEBUG_ULSCH_CODING -void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, uint16_t N_RB_UL) +void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, + uint16_t N_RB_UL, + NR_DL_FRAME_PARMS* frame_parms) { -{ - int i, r; NR_UE_ULSCH_t *ulsch = *ulschptr; if (ulsch) { @@ -54,15 +54,15 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, uint16_t N_RB_UL) printf("Freeing ulsch %p\n",ulsch); #endif - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS; //number of segments to be allocated + int max_layers = (frame_parms->nb_antennas_txnb_antennas_tx : NR_MAX_NB_LAYERS; + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*max_layers; //number of segments to be allocated - if (N_RB_UL != 273) { - a_segments = a_segments*N_RB_UL; - a_segments = a_segments/273 +1; - } + if (N_RB_UL != 273) { + a_segments = a_segments*N_RB_UL; + a_segments = a_segments/273 +1; + } - - for (i=0; iharq_processes[i]) { if (ulsch->harq_processes[i]->a) { @@ -81,7 +81,7 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, uint16_t N_RB_UL) free16(ulsch->harq_processes[i]->f,14*N_RB_UL*12*8); ulsch->harq_processes[i]->f = NULL; } - for (r=0; rharq_processes[i]->c[r]) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); ulsch->harq_processes[i]->c[r] = NULL; @@ -94,6 +94,15 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, uint16_t N_RB_UL) } + if (ulsch->harq_processes[i]->c) { + free16(ulsch->harq_processes[i]->c,a_segments); + ulsch->harq_processes[i]->c = NULL; + } + if (ulsch->harq_processes[i]->d) { + free16(ulsch->harq_processes[i]->d,a_segments); + ulsch->harq_processes[i]->d = NULL; + } + free16(ulsch->harq_processes[i],sizeof(NR_UL_UE_HARQ_t)); ulsch->harq_processes[i] = NULL; } @@ -101,13 +110,13 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr, uint16_t N_RB_UL) free16(ulsch,sizeof(NR_UE_ULSCH_t)); *ulschptr = NULL; } - } -NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids) -{ - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS; //number of segments to be allocated +NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, NR_DL_FRAME_PARMS* frame_parms) { + + int max_layers = (frame_parms->nb_antennas_txnb_antennas_tx : NR_MAX_NB_LAYERS; + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*max_layers; //number of segments to be allocated if (N_RB_UL != 273) { a_segments = a_segments*N_RB_UL; @@ -140,6 +149,8 @@ NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids) DevAssert(ulsch->harq_processes[i]->b); bzero(ulsch->harq_processes[i]->b,ulsch_bytes); + ulsch->harq_processes[i]->c = malloc16(a_segments); + ulsch->harq_processes[i]->d = malloc16(a_segments); for (int r = 0; r < a_segments; r++) { // account for filler in first segment and CRCs for multiple segment case ulsch->harq_processes[i]->c[r] = malloc16(8448); @@ -240,6 +251,8 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, printf("\n"); */ + int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*harq_process->pusch_pdu.nrOfLayers*1056; + if (A > 3824) { // Add 24-bit crc (polynomial A) to payload crc = crc24a(harq_process->a,A)>>8; @@ -251,7 +264,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, harq_process->B = A+24; - AssertFatal((A/8)+4 <= MAX_NR_ULSCH_PAYLOAD_BYTES,"A %d is too big (A/8+4 = %d > %d)\n",A,(A/8)+4,MAX_NR_ULSCH_PAYLOAD_BYTES); + AssertFatal((A/8)+4 <= max_payload_bytes,"A %d is too big (A/8+4 = %d > %d)\n",A,(A/8)+4,max_payload_bytes); memcpy(harq_process->b,harq_process->a,(A/8)+4); } @@ -265,7 +278,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, harq_process->B = A+16; - AssertFatal((A/8)+3 <= MAX_NR_ULSCH_PAYLOAD_BYTES,"A %d is too big (A/8+3 = %d > %d)\n",A,(A/8)+3,MAX_NR_ULSCH_PAYLOAD_BYTES); + AssertFatal((A/8)+3 <= max_payload_bytes,"A %d is too big (A/8+3 = %d > %d)\n",A,(A/8)+3,max_payload_bytes); memcpy(harq_process->b,harq_process->a,(A/8)+3); // using 3 bytes to mimic the case of 24 bit crc } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 297b58e88e..2bd0bd301a 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -273,7 +273,7 @@ typedef struct { /// The payload + CRC (24 bits) in bits (38.212 V15.4.0 section 5.1) uint32_t B; /// Pointers to code blocks after code block segmentation and CRC attachment (38.212 V15.4.0 section 5.2.2) - uint8_t *c[MAX_NUM_NR_ULSCH_SEGMENTS]; + uint8_t **c; /// Number of bits in each code block (38.212 V15.4.0 section 5.2.2) uint32_t K; /// Number of "Filler" bits added in the code block segmentation (38.212 V15.4.0 section 5.2.2) @@ -281,13 +281,11 @@ typedef struct { /// Number of code blocks after code block segmentation (38.212 V15.4.0 section 5.2.2) uint32_t C; /// Pointers to code blocks after LDPC coding (38.212 V15.4.0 section 5.3.2) - int16_t *d[MAX_NUM_NR_ULSCH_SEGMENTS]; + int16_t **d; /// LDPC processing buffer - t_nrLDPC_procBuf* p_nrLDPC_procBuf[MAX_NUM_NR_ULSCH_SEGMENTS]; + t_nrLDPC_procBuf** p_nrLDPC_procBuf; /// LDPC lifting size (38.212 V15.4.0 table 5.3.2-1) uint32_t Z; - /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) - int16_t e[MAX_NUM_NR_DLSCH_SEGMENTS][3*8448]; /// Number of bits in each code block after rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) uint32_t E; /// Number of segments processed so far @@ -342,8 +340,6 @@ typedef struct { int16_t q_RI[MAX_RI_PAYLOAD]; /// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled uint8_t h[MAX_NUM_CHANNEL_BITS]; - /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) - int16_t *w[MAX_NUM_NR_ULSCH_SEGMENTS]; ////////////////////////////////////////////////////////////// } NR_UL_gNB_HARQ_t; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 5574be705f..a912a896af 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -104,8 +104,7 @@ #define MAX_NUM_NR_DLSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) #define MAX_NR_DLSCH_PAYLOAD_BYTES (MAX_NUM_NR_DLSCH_SEGMENTS*1056) -#define MAX_NUM_NR_ULSCH_SEGMENTS (NR_MAX_NB_LAYERS*34) -#define MAX_NR_ULSCH_PAYLOAD_BYTES (MAX_NUM_NR_ULSCH_SEGMENTS*1056) +#define MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER 34 #define MAX_NUM_NR_CHANNEL_BITS (4*14*273*12*8) // 14 symbols, 273 RB #define MAX_NUM_NR_RE (4*14*273*12) diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index 11b94a2221..1a6c788c8d 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -417,7 +417,7 @@ int main(int argc, char **argv) for (sf = 0; sf < 2; sf++) { for (i = 0; i < 2; i++) { - UE->ulsch[sf][0][i] = new_nr_ue_ulsch(N_RB_UL, 8); + UE->ulsch[sf][0][i] = new_nr_ue_ulsch(N_RB_UL, 8, frame_parms); if (!UE->ulsch[sf][0][i]) { printf("Can't get ue ulsch structures.\n"); @@ -628,7 +628,7 @@ int main(int argc, char **argv) for (sf = 0; sf < 2; sf++) for (i = 0; i < 2; i++) - free_nr_ue_ulsch(&UE->ulsch[sf][0][i], N_RB_UL); + free_nr_ue_ulsch(&UE->ulsch[sf][0][i], N_RB_UL, frame_parms); term_nr_ue_signal(UE, 1); free(UE); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 3851ee011d..1c9ebf3eba 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -743,7 +743,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources, } else if (get_softmodem_params()->nsa) { - uint8_t mac_sdus[MAX_NR_ULSCH_PAYLOAD_BYTES]; + uint8_t mac_sdus[MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*1056]; uint16_t sdu_lengths[NB_RB_MAX] = {0}; int TBS_bytes = 848; int mac_ce_len = 0; From d24068a33b173d9d8ba9a49310e5c843db0e8767 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 11 Mar 2022 01:23:39 +0100 Subject: [PATCH 050/226] some bugfixes for CSI reporting with PUCCH2. Configuration of cqi_Table 2 for CSI reporting when 256-QAM is enabled. --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 6 ++-- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 2 -- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 3 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 32 ++++++++++++++----- openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 +-- openair2/RRC/NR/nr_rrc_config.c | 12 +++++++ openair2/RRC/NR/nr_rrc_config.h | 1 + openair2/RRC/NR/rrc_gNB_reconfig.c | 2 +- 8 files changed, 45 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index db36b39f99..beab48b977 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -1178,9 +1178,9 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, } } } -#ifdef DEBUG_NR_PUCCH_RX - printf("Decoding pucch2 for %d symbols, %d PRB\n",pucch_pdu->nr_of_symbols,pucch_pdu->prb_size); -#endif + LOG_D(PHY,"Decoding pucch2 for %d symbols, %d PRB, nb_harq %d, nb_sr %d, nb_csi %d/%d\n", + pucch_pdu->nr_of_symbols,pucch_pdu->prb_size, + pucch_pdu->bit_len_harq,pucch_pdu->sr_flag,pucch_pdu->bit_len_csi_part1,pucch_pdu->bit_len_csi_part2); int nc_group_size=1; // 2 PRB int ngroup = prb_size_ext/nc_group_size/2; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 94b7ab18bf..d36e02b606 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4057,8 +4057,6 @@ uint16_t compute_pucch_prb_size(uint8_t format, if ((O_tot+O_csi)>(nr_prbs*n_re_ctrl*n_symb*Qm*r)) AssertFatal(1==0,"MaxCodeRate %.2f can't support %d UCI bits and %d CRC bits with %d PRBs", r,O_tot,O_crc,nr_prbs); - else - return nr_prbs; } if (format==2){ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 81f4169e13..d2f726e0fc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -156,7 +156,8 @@ void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, uint16_t target_coderate,target_qm; if (cqi_idx>0) { int cqi_table = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.cqi_table; - AssertFatal(cqi_table == mcs_table_idx, "Indices of MCS tables don't correspond\n"); + if (cqi_table != mcs_table_idx) + LOG_W(NR_MAC,"Indices of MCS tables don't correspond yet, cri_ri_li_pmi_cqi_report.cqi_table %d, mcs_table_index %d\n",cqi_table,mcs_table_idx); switch (cqi_table) { case 0: target_qm = cqi_table1[cqi_idx][0]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 3688ac7771..53df37d139 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1559,7 +1559,6 @@ int nr_acknack_scheduling(int mod_id, // if TDD configuration is not present and the band is not FDD, it means it is a dynamic TDD configuration AssertFatal(RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD,"Dynamic TDD not handled yet\n"); - NR_sched_pucch_t *csi_pucch; /* for the moment, we consider: * * only pucch_sched[0] holds HARQ (and SR) @@ -1578,13 +1577,18 @@ int nr_acknack_scheduling(int mod_id, pucch->csi_bits); /* if the currently allocated PUCCH of this UE is full, allocate it */ + NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[1]; if (pucch->dai_c == 2) { /* advance the UL slot information in PUCCH by one so we won't schedule in * the same slot again */ const int f = pucch->frame; const int s = pucch->ul_slot; LOG_D(NR_MAC, "In %s: %d.%d DAI = 2 pucch currently in %d.%d, advancing by 1 slot\n", __FUNCTION__, frame, slot, f, s); - nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + if (!(csi_pucch + && csi_pucch->csi_bits > 0 + && csi_pucch->frame == f + && csi_pucch->ul_slot == s)) + nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); memset(pucch, 0, sizeof(*pucch)); pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; if(((s + 1)%nr_slots_period) == 0) @@ -1592,11 +1596,11 @@ int nr_acknack_scheduling(int mod_id, else pucch->ul_slot = (s + 1) % n_slots_frame; // we assume that only two indices over the array sched_pucch exist - csi_pucch = &sched_ctrl->sched_pucch[1]; // skip the CSI PUCCH if it is present and if in the next frame/slot // and if we don't multiplex csi_pucch->r_pucch=-1; - if (csi_pucch->csi_bits > 0 + if (csi_pucch + && csi_pucch->csi_bits > 0 && csi_pucch->frame == pucch->frame && csi_pucch->ul_slot == pucch->ul_slot && !csi_pucch->simultaneous_harqcsi) { @@ -1653,7 +1657,10 @@ int nr_acknack_scheduling(int mod_id, const int s = pucch->ul_slot; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; LOG_D(NR_MAC, "In %s: %d.%d DAI > 0, cannot reach timing for pucch in %d.%d, advancing slot by 1 and trying again\n", __FUNCTION__, frame, slot, f, s); - nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + if (!(csi_pucch && + csi_pucch->csi_bits > 0 && + csi_pucch->frame == f && + csi_pucch->ul_slot == s)) nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); memset(pucch, 0, sizeof(*pucch)); pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; if(((s + 1)%nr_slots_period) == 0) @@ -1665,6 +1672,14 @@ int nr_acknack_scheduling(int mod_id, pucch->timing_indicator = i; pucch->dai_c++; + // if there is CSI in this slot update the HARQ information for that one too + if (csi_pucch && + csi_pucch->csi_bits > 0 && + csi_pucch->frame == pucch->frame && + csi_pucch->ul_slot == pucch->ul_slot) { + csi_pucch->timing_indicator = i; + csi_pucch->dai_c++; + } // retain old resource indicator, and we are good LOG_D(NR_MAC, "In %s: %d.%d. DAI > 0, pucch allocated for %d.%d (index %d)\n", __FUNCTION__, frame,slot,pucch->frame,pucch->ul_slot,pucch->timing_indicator); return 0; @@ -1725,8 +1740,6 @@ int nr_acknack_scheduling(int mod_id, return -1; } - // is there already CSI in this slot? - csi_pucch = &sched_ctrl->sched_pucch[1]; if (csi_pucch && csi_pucch->csi_bits > 0 && csi_pucch->frame == pucch->frame && @@ -1755,7 +1768,10 @@ int nr_acknack_scheduling(int mod_id, else { csi_pucch->timing_indicator = ind_found; csi_pucch->dai_c++; - memset(pucch,0,sizeof(*pucch)); + // keep updating format 2 indicator + pucch->timing_indicator = ind_found; // index in the list of timing indicators + pucch->dai_c++; + LOG_D(NR_MAC,"multiplexing csi_pucch %d +csi_pucch->dai_c %d for %d.%d\n",csi_pucch->csi_bits,csi_pucch->dai_c,csi_pucch->frame,csi_pucch->ul_slot); return 1; } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 73bb941af9..1bbecb3328 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1782,14 +1782,14 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, - uecap, bwp_Dedicated, scc); + uecap, SpCellConfig, bwp_Dedicated, scc); struct NR_ServingCellConfig__downlinkBWP_ToAddModList *DL_BWP_list = SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; if (DL_BWP_list) { for (int i=0; ilist.count; i++){ NR_BWP_Downlink_t *bwp = DL_BWP_list->list.array[i]; int scs = bwp->bwp_Common->genericParameters.subcarrierSpacing; - set_dl_mcs_table(scs, uecap, bwp->bwp_Dedicated, carrier->servingcellconfigcommon); + set_dl_mcs_table(scs, uecap, SpCellConfig,bwp->bwp_Dedicated, carrier->servingcellconfigcommon); } } } diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 3cde364fb8..87543da5f9 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -172,6 +172,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, + NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc) { @@ -210,6 +211,17 @@ void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, if(bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == NULL) bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = calloc(1, sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table)); *bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NR_PDSCH_Config__mcs_Table_qam256; +// set table 2 in correct entry in SpCellConfig->spCellConfigDedicated->csi_MeasConfig->csi_ReportConfigToAddModList->list + AssertFatal(SpCellConfig!=NULL,"SpCellConfig shouldn't be null\n"); + AssertFatal(SpCellConfig->spCellConfigDedicated!=NULL,"SpCellConfigDedicated shouldn't be null\n"); + if (SpCellConfig->spCellConfigDedicated->csi_MeasConfig && + SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present== NR_SetupRelease_CSI_MeasConfig_PR_setup && + SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup && + SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup->csi_ReportConfigToAddModList) + for (int i=0;ispCellConfigDedicated->csi_MeasConfig->choice.setup->csi_ReportConfigToAddModList->list.count;i++) { + if (SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup->csi_ReportConfigToAddModList->list.array[i]->cqi_Table) + *SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup->csi_ReportConfigToAddModList->list.array[i]->cqi_Table=NR_CSI_ReportConfig__cqi_Table_table2; + } } else bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NULL; diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 1a0d091e35..16a92b9a7e 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -114,6 +114,7 @@ typedef struct physicalcellgroup_s{ void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, + NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc); void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 35412f4c0c..747db7878c 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -605,7 +605,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup1=NULL; bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup2=NULL; bwp->bwp_Dedicated->pdsch_Config->choice.setup->rbg_Size=NR_PDSCH_Config__rbg_Size_config1; - set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing, uecap, bwp->bwp_Dedicated, servingcellconfigcommon); + set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing, uecap, secondaryCellGroup->spCellConfig, bwp->bwp_Dedicated, servingcellconfigcommon); bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI)); *bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n1; bwp->bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; From 1ab1fde7b83c4b57582cd43c1a34672a8fa17d65 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 11 Mar 2022 14:00:30 +0100 Subject: [PATCH 051/226] fix for fdd and other warnings --- executables/nr-softmodem.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 8 ++------ openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 + openair2/RRC/NR/nr_rrc_config.c | 8 ++------ 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 2fe6c86b41..1c75d9a155 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -741,7 +741,7 @@ int main( int argc, char **argv ) { RC.ru[ru_id]->rf_map.card=0; RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset; if (ru_id==0) sl_ahead = RC.ru[ru_id]->sl_ahead; - else AssertFatal(RC.ru[ru_id]->sl_ahead != RC.ru[0]->sl_ahead,"RU %d has different sl_ahead %d than RU 0 %d\n",RC.ru[ru_id]->sl_ahead,RC.ru[0]->sl_ahead); + else AssertFatal(RC.ru[ru_id]->sl_ahead != RC.ru[0]->sl_ahead,"RU %d has different sl_ahead %d than RU 0 %d\n",ru_id,RC.ru[ru_id]->sl_ahead,RC.ru[0]->sl_ahead); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index aaa97fea87..943bb04cb7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -446,11 +446,8 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, AssertFatal(RC.nrmac[Mod_idP]->UL_tti_req_ahead[0], "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n"); /* fill in slot/frame numbers: slot is fixed, frame will be updated by scheduler - extern sf_ahead is initialized in ru_thread but that function is not executed yet here*/ - const uint16_t sf_ahead = (uint16_t) ceil((float)6/(0x01<<(*scc->ssbSubcarrierSpacing))); - const uint16_t sl_ahead = sf_ahead * (0x01<<(*scc->ssbSubcarrierSpacing)); - /* consider that scheduler runs sl_ahead: the first sl_ahead slots are - * already "in the past" and thus we put frame 1 instead of 0!*/ + * consider that scheduler runs sl_ahead: the first sl_ahead slots are + * already "in the past" and thus we put frame 1 instead of 0! */ for (int i = 0; i < n; ++i) { nfapi_nr_ul_tti_request_t *req = &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][i]; req->SFN = i < (RC.nrmac[Mod_idP]->if_inst->sl_ahead-1); @@ -667,7 +664,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - return(0); }// END rrc_mac_config_req_gNB diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 1bbecb3328..1830a3ca3a 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -41,6 +41,7 @@ #include #include +#include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "asn1_msg.h" #include "../nr_rrc_proto.h" #include "RRC/NR/nr_rrc_extern.h" diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 87543da5f9..2dbb8c93d5 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -110,13 +110,10 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ //TODO change to accomodate for SRS lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); - int temp_min_delay; + int temp_min_delay = 6; // k2 = 2 or 3 won'r work as well as higher values if(frame_type==TDD && scc->tdd_UL_DL_ConfigurationCommon) { - + switch (scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity) { - default: - temp_min_delay = 6; - break; case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms2p5: // 30kHz SCS case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms2: // 60kHz SCS case NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms1p25: // 60kHz SCS @@ -128,7 +125,6 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ } } - int k2 = (min_fb_delay Date: Fri, 18 Mar 2022 18:51:22 +0100 Subject: [PATCH 052/226] removal of some logs. Temporary suppression of QAM256 for 5G Records testing --- openair1/PHY/CODING/nr_rate_matching.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 18 ++++++++-- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 4 +-- openair1/SCHED_NR/nr_prach_procedures.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 34 +++++++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 14 ++++---- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 +-- 8 files changed, 47 insertions(+), 33 deletions(-) diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index 29cba0a557..e693e8542a 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -409,7 +409,7 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm, #endif if (Foffset > E) { - LOG_E(PHY,"nr_rate_matching: invalid parameters (Foffset %d > E %d)\n",Foffset,E); + LOG_E(PHY,"nr_rate_matching: invalid parameters (Foffset %d > E %d) F %d, k0 %d, Ncb %d, rvidx %d, Ilbrm %d\n",Foffset,E,F, ind, Ncb, rvidx, Ilbrm); return -1; } if (Foffset > Ncb) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index cdf0e6c152..8803e6ff26 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -218,14 +218,14 @@ void ldpc8blocks( void *p) { #endif uint32_t E = nr_get_E(G, impp->n_segments, mod_order, rel15->nrOfLayers, rr); //#ifdef DEBUG_DLSCH_CODING - LOG_D(NR_PHY,"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb %d)...\n", + LOG_D(NR_PHY,"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb %d,nrOfLayer %d)...\n", rr, impp->n_segments, G, E, impp->F, Kr-impp->F-2*(*impp->Zc), - mod_order,nb_rb); + mod_order,nb_rb,rel15->nrOfLayers); // for tbslbrm calculation according to 5.4.2.1 of 38.212 uint8_t Nl = 4; @@ -248,6 +248,20 @@ void ldpc8blocks( void *p) { Kr-impp->F-2*(*impp->Zc), rel15->rvIndex[0], E); + if (Kr-impp->F-2*(*impp->Zc)> E) { + LOG_E(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n", + A,impp->K,G, nb_rb,nb_symb_sch,nb_re_dmrs,length_dmrs,(int)mod_order); + + LOG_E(NR_PHY,"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb %d)...\n", + rr, + impp->n_segments, + G, + E, + Kr, + impp->F, + Kr-impp->F-2*(*impp->Zc), + mod_order,nb_rb); + } #ifdef DEBUG_DLSCH_CODING for (int i =0; i<16; i++) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index beab48b977..7e4f9a9eaa 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -439,7 +439,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_confidence_level = no_conf ? 1 : 0; uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); uci_pdu->harq->harq_list[0].harq_value = !(index&0x01); - if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { @@ -458,7 +458,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_list[1].harq_value = !(index&0x01); uci_pdu->harq->harq_list[0].harq_value = !((index>>1)&0x01); - if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index b0f59d5f47..7b5b6d22ff 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -173,7 +173,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot) { if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0+gNB->prach_thres)) { - LOG_I(NR_PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", + LOG_D(NR_PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", gNB->Mod_id, frame, slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index fe0ba251cb..19145aadb9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -228,7 +228,7 @@ void find_SSB_and_RO_available(module_id_t module_idP) { cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion; cc->num_active_ssb = num_active_ssb; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "Total available RO %d, num of active SSB %d: unused RO = %d association_period %u N_RA_sfn %u total_prach_occasions_per_config_period %u\n", cc->total_prach_occasions, cc->num_active_ssb, @@ -676,7 +676,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra->preamble_index = preamble_index; ra->beam_id = beam_index; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "[gNB %d][RAPROC] CC_id %d Frame %d Activating Msg2 generation in frame %d, slot %d using RA rnti %x SSB " "index %u RA index %d\n", module_idP, @@ -791,7 +791,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t return; } - LOG_I(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", + LOG_D(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", module_idP, frame, slot, CC_id, sched_frame, sched_slot); nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][sched_slot]; @@ -946,7 +946,7 @@ void nr_get_Msg3alloc(module_id_t module_id, k2 = *pusch_TimeDomainAllocationList->list.array[i]->k2; int start_symbol_index,nr_of_symbols; SLIV2SL(pusch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength, &start_symbol_index, &nr_of_symbols); - LOG_I(NR_MAC,"Checking Msg3 TDA %d : k2 %d, sliv %d,S %d L %d\n",i,(int)k2,(int)pusch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength,start_symbol_index,nr_of_symbols); + LOG_D(NR_MAC,"Checking Msg3 TDA %d : k2 %d, sliv %d,S %d L %d\n",i,(int)k2,(int)pusch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength,start_symbol_index,nr_of_symbols); // we want to transmit in the uplink symbols of mixed slot AND assuming Msg2 was in the mixed slot if ((k2 + DELTA[mu])%nb_slots_per_period == 0) { temp_slot = current_slot + k2 + DELTA[mu]; // msg3 slot according to 8.3 in 38.213 @@ -987,7 +987,7 @@ void nr_get_Msg3alloc(module_id_t module_id, tdd_beam_association[num_tdd_period] = ra->beam_id; } - LOG_I(NR_MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id); + LOG_D(NR_MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id); uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * MAX_BWP_SIZE]; @@ -1156,7 +1156,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; } - LOG_I(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", + LOG_D(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", frameP, slotP, ra->Msg3_frame, @@ -1310,7 +1310,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_req->nPDUs+=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - LOG_A(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n", + LOG_D(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n", module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state,pdcch_pdu_rel15->CoreSetType); // SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control @@ -1471,9 +1471,9 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); if(ra->cfra) { - LOG_I(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CFRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); + LOG_D(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CFRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); } - else LOG_I(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CBRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); + else LOG_D(NR_MAC, "Frame %d, Subframe %d: Setting RA-Msg3 reception (CBRA) for SFN.Slot %d.%d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); T(T_GNB_MAC_DL_RAR_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(ra->RA_rnti), T_INT(frameP), T_INT(slotP), T_INT(0), T_BUFFER(&tx_req->TLVs[0].value.direct[0], tx_req->TLVs[0].length)); @@ -1749,7 +1749,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_req->nPDUs+=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - LOG_A(NR_MAC, "[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg4 DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state); + LOG_D(NR_MAC, "[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg4 DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state); // SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control // information to data and is reset every slot. @@ -1823,7 +1823,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_payload.pucch_resource_indicator = delta_PRI; // This is delta_PRI from 9.2.1 in 38.213 dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch->timing_indicator; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "[RAPROC] DCI 1_0 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d pucchres %d harqtiming %d\n", dci_payload.frequency_domain_assignment.val, pdsch_pdu_rel15->rbStart, @@ -1836,7 +1836,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_payload.pucch_resource_indicator, dci_payload.pdsch_to_harq_feedback_timing_indicator.val); - LOG_I(NR_MAC, + LOG_D(NR_MAC, "[RAPROC] DCI params: rnti 0x%x, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d, BWPsize %d\n", pdcch_pdu_rel15->dci_pdu[0].RNTI, NR_RNTI_TC, @@ -1906,7 +1906,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra if(ra->msg3_dcch_dtch) { // If the UE used MSG3 to transfer a DCCH or DTCH message, then contention resolution is successful upon transmission of PDCCH - LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) CBRA procedure succeeded!\n", UE_id, ra->rnti); + LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) CBRA procedure succeeded!\n", UE_id, ra->rnti); nr_clear_ra_proc(module_idP, CC_id, frameP, ra); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; @@ -1939,12 +1939,12 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram if (harq->is_waiting == 0) { if (harq->round == 0) { if (stats->dlsch_errors == 0) { - LOG_A(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); + LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; } else { - LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); + LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); } nr_clear_ra_proc(module_id, CC_id, frame, ra); @@ -1953,7 +1953,7 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram } } else { - LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) Received Nack of RA-Msg4. Preparing retransmission!\n", UE_id, ra->rnti); + LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) Received Nack of RA-Msg4. Preparing retransmission!\n", UE_id, ra->rnti); ra->Msg4_frame = (frame + 1) % 1024; ra->Msg4_slot = 1; ra->state = Msg4; @@ -2010,7 +2010,7 @@ void nr_fill_rar(uint8_t Mod_idP, uint8_t * dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu){ - LOG_I(NR_MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index, ra->timing_offset); + LOG_D(NR_MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index, ra->timing_offset); NR_RA_HEADER_BI *rarbi = (NR_RA_HEADER_BI *) dlsch_buffer; NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) (dlsch_buffer + 1); NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 2); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 342880f293..30d484ae08 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -756,20 +756,20 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, continue; if(no_sig) { - LOG_W(NR_MAC, "Random Access %i failed at state %i (no signal)\n", i, ra->state); + LOG_D(NR_MAC, "Random Access %i failed at state %i (no signal)\n", i, ra->state); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); } else { // random access pusch with TC-RNTI if (ra->rnti != current_rnti) { - LOG_W(NR_MAC, + LOG_D(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->rnti, current_rnti); if( (frameP==ra->Msg3_frame) && (slotP==ra->Msg3_slot) ) { - LOG_W(NR_MAC, "Random Access %i failed at state %i (TC_RNTI %04x RNTI %04x)\n", i, ra->state,ra->rnti,current_rnti); + LOG_D(NR_MAC, "Random Access %i failed at state %i (TC_RNTI %04x RNTI %04x)\n", i, ra->state,ra->rnti,current_rnti); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); } @@ -781,7 +781,7 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, UE_id = add_new_nr_ue(gnb_mod_idP, ra->rnti, ra->CellGroup); if (UE_id<0) { - LOG_W(NR_MAC, "Random Access %i discarded at state %i (TC_RNTI %04x RNTI %04x): max number of users achieved!\n", i, ra->state,ra->rnti,current_rnti); + LOG_D(NR_MAC, "Random Access %i discarded at state %i (TC_RNTI %04x RNTI %04x): max number of users achieved!\n", i, ra->state,ra->rnti,current_rnti); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); return; @@ -877,20 +877,20 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, // for CFRA (NSA) do not schedule retransmission of msg3 if (ra->cfra) { - LOG_W(NR_MAC, "Random Access %i failed at state %i (NSA msg3 reception failed)\n", i, ra->state); + LOG_D(NR_MAC, "Random Access %i failed at state %i (NSA msg3 reception failed)\n", i, ra->state); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); return; } if (ra->msg3_round >= MAX_HARQ_ROUNDS - 1) { - LOG_W(NR_MAC, "Random Access %i failed at state %i (Reached msg3 max harq rounds)\n", i, ra->state); + LOG_D(NR_MAC, "Random Access %i failed at state %i (Reached msg3 max harq rounds)\n", i, ra->state); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); return; } - LOG_W(NR_MAC, "Random Access %i Msg3 CRC did not pass)\n", i); + LOG_D(NR_MAC, "Random Access %i Msg3 CRC did not pass)\n", i); ra->msg3_round++; ra->state = Msg3_retransmission; } diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index ad4ab7da05..c860d847d9 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -77,7 +77,7 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) bool in_timewindow = frame_diff == 0 || (frame_diff == 1 && UL_info->slot < 7); if (UL_info->rach_ind.number_of_pdus > 0 && in_timewindow) { - LOG_A(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n", + LOG_D(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n", UL_info->frame, UL_info->slot, UL_info->rach_ind.sfn, UL_info->rach_ind.slot); for (int i = 0; i < UL_info->rach_ind.number_of_pdus; i++) { UL_info->rach_ind.number_of_pdus--; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 1830a3ca3a..02c42b4e5f 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1783,14 +1783,14 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, - uecap, SpCellConfig, bwp_Dedicated, scc); + NULL/*uecap*/, SpCellConfig, bwp_Dedicated, scc); struct NR_ServingCellConfig__downlinkBWP_ToAddModList *DL_BWP_list = SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; if (DL_BWP_list) { for (int i=0; ilist.count; i++){ NR_BWP_Downlink_t *bwp = DL_BWP_list->list.array[i]; int scs = bwp->bwp_Common->genericParameters.subcarrierSpacing; - set_dl_mcs_table(scs, uecap, SpCellConfig,bwp->bwp_Dedicated, carrier->servingcellconfigcommon); + set_dl_mcs_table(scs, NULL,/*uecap,*/ SpCellConfig,bwp->bwp_Dedicated, carrier->servingcellconfigcommon); } } } From 3dc7da3b2269c9902bc58f5339a48e41833f88b8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 20 Mar 2022 15:08:56 +0100 Subject: [PATCH 053/226] fix for bad merge issues --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 12 +----------- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 4 ++-- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 1 - 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 89ba28b0c3..de3a1d274a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -241,7 +241,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, #ifdef DEBUG_DLSCH_MAPPING uint8_t dmrs_symbol = l0+l_prime; - printf("DMRS Type %d params for ap %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n", + printf("DMRS Type %d params for nl %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n", 1+dmrs_Type,nl, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime, l0, dmrs_symbol); #endif @@ -338,13 +338,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (beta_ptrs*amp*mod_ptrs[(ptrs_idx<<1) + 1])>> 15; #ifdef DEBUG_DLSCH_MAPPING printf("ptrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d, mod_ptrs: %d %d\n", -<<<<<<< HEAD - ptrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)], - ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)],mod_ptrs[ptrs_idx<<1],mod_ptrs[(ptrs_idx<<1)+1]); -======= ptrs_idx, l, k, k_prime, n, ((int16_t*)txdataF_precoding[nl])[((l*frame_parms->ofdm_symbol_size + k)<<1)], ((int16_t*)txdataF_precoding[nl])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1],mod_ptrs[ptrs_idx<<1],mod_ptrs[(ptrs_idx<<1)+1]); ->>>>>>> origin/develop #endif ptrs_idx++; } @@ -354,13 +349,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * tx_layers[nl][(m<<1) + 1]) >> 15; #ifdef DEBUG_DLSCH_MAPPING printf("m %d\t l %d \t k %d \t txdataF: %d %d\n", -<<<<<<< HEAD - m, l, k, txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1)], - txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1]); -======= m, l, k, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)], txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1]); ->>>>>>> origin/develop #endif m++; } diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index beab48b977..7e4f9a9eaa 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -439,7 +439,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_confidence_level = no_conf ? 1 : 0; uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); uci_pdu->harq->harq_list[0].harq_value = !(index&0x01); - if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { @@ -458,7 +458,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_list[1].harq_value = !(index&0x01); uci_pdu->harq->harq_list[0].harq_value = !((index>>1)&0x01); - if (no_conf) LOG_I(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d (0 pass, 1 fail) and %d with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", frame,slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index f165656f95..e797c01096 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -286,7 +286,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, UE_info->CellGroup[0], sched_ctrl->active_bwp, NULL, - /* tda = */ 0, + /* tda = */ 2, g_nrOfLayers, sched_ctrl, ps); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 9270540d26..c57736990c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1154,7 +1154,6 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr (table_7_3_2_3_3_1[dci->antenna_ports.val][2]<<1) + (table_7_3_2_3_3_1[dci->antenna_ports.val][3]<<2) + (table_7_3_2_3_3_1[dci->antenna_ports.val][4]<<3)); - dlsch_config_pdu_1_1->n_front_load_symb = 1; } if ((dmrs_type == NULL) && (max_length != NULL)){ // Table 7.3.1.2.2-2: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=2 From 7b9f53e9db28c64a184ee5d55253afbacd94df7a Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 21 Mar 2022 10:01:13 +0100 Subject: [PATCH 054/226] option for identity matrix if xp is 1 --- openair2/LAYER2/NR_MAC_gNB/config.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 1 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 7 ++++++- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 ++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 8fe6107e4a..2e37cc39c5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -137,11 +137,10 @@ void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sche } -void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t dl_antenna_ports_struct, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { +void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[Mod_idP]->config[0]; RC.nrmac[Mod_idP]->common_channels[0].ServingCellConfigCommon = scc; - int pdsch_AntennaPorts = dl_antenna_ports_struct.N1 * dl_antenna_ports_struct.N2 * dl_antenna_ports_struct.XP; // Carrier configuration @@ -465,9 +464,10 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Configuring common parameters from NR ServingCellConfig\n"); + RC.nrmac[Mod_idP]->pdsch_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP; config_common(Mod_idP, ssb_SubcarrierOffset, - pdsch_AntennaPorts, + RC.nrmac[Mod_idP]->pdsch_antenna_ports, pusch_AntennaPorts, scc); LOG_D(NR_MAC, "%s() %s:%d RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 6fa460026b..a3bf413b29 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1183,6 +1183,7 @@ void nr_schedule_ue_spec(module_id_t module_id, nrOfLayers, csi_report->N1, csi_report->N2, + gNB_mac->pdsch_antenna_ports, csi_report->codebook_mode); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 59a8811cfc..1eb54ab45c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -149,11 +149,16 @@ uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl) { uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int layers, int N1, int N2, + int config_file_ant_ports, int codebook_mode) { + int antenna_ports = (N1*N2)<<1; + if (antenna_ports!=config_file_ant_ports) + return 0; //identity matrix + int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1; int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2; - int antenna_ports = (N1*N2)<<1; + LOG_D(NR_MAC,"PMI report: x1 %d x2 %d\n",x1,x2); sched_ctrl->set_pmi = false; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 1319aa6a83..455538a361 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -40,7 +40,7 @@ void mac_top_init_gNB(void); void config_common(int Mod_idP, int ssb_SubcarrierOffset, - rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, + int pdsch_AntennaPorts, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc ); @@ -458,6 +458,7 @@ void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps); uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int layers, int N1, int N2, + int config_file_ant_ports, int codebook_mode); void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 68f6455f89..8b685fdd02 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -806,6 +806,8 @@ typedef struct gNB_MAC_INST_s { uint16_t cset0_bwp_size; NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[64]; + int pdsch_antenna_ports; + bool first_MIB; double dl_bler_target_upper; double dl_bler_target_lower; From 4d289b92cc7fb62868019acfe7eccd9a8f23c02a Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 21 Mar 2022 11:59:31 +0100 Subject: [PATCH 055/226] fix xp=1 option and added RUNMODEM description for MIMO configuration --- .../gNB_SA_n78_106PRB.2x2_usrpn310.conf | 2 +- .../gNB_SA_n78_133PRB.2x2_usrpn310.conf | 2 +- .../gnb.band78.nsa_2x2.106PRB.usrpn310.conf | 2 +- .../gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf | 2 +- .../gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf | 2 +- doc/RUNMODEM.md | 17 +++++++++++++++++ doc/images/mimo_antenna_ports.png | Bin 0 -> 18753 bytes openair2/LAYER2/NR_MAC_gNB/config.c | 5 +++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 7 ++++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 12 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 doc/images/mimo_antenna_ports.png diff --git a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf index 3b08b70ecf..82d665d904 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf @@ -38,7 +38,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf index 0d9abc275d..937d287d24 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf @@ -39,7 +39,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf index 96bf3debd8..213c166826 100644 --- a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf @@ -20,7 +20,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 31; //0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf index ff10eee268..7a3afd1127 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf @@ -38,7 +38,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" do_SRS = 1; diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf index 78b402d064..fbe7e62a23 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf @@ -38,7 +38,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; #pusch_TargetSNRx10 = 200; #pucch_TargetSNRx10 = 200; diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 449859b042..4cc57c2629 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -211,7 +211,24 @@ UE on machine 2: `sudo ./nr-uesoftmodem --if_freq 2169080000 --if_freq_off -400000000` +# MIMO configuration + + + + +
+ + +
+ +This image shows an example of gNB 5G MIMO logical antenna port configuration. It has to be noted that logical antenna ports might not directly correspond to physical antenna ports and each logical antenna port might consist of a sub-array of antennas. + +The basic element is a dual-polarized antenna, therefore the minimal DL MIMO setup with two logical antenna ports would consist of two cross-polarized antenna elements. In a single panel configuration, as the one in the picture, this element can be repeated vertiacally and/or horizontally to form an equi-spaced 1D or 2D array. The values N1 and N2 represent the number of antenna ports in the two dimensions and the supported configurations are specified in Section 5.2.2.2.1 of TS 38.214. + +The DL logical antenna port configuration can be selected thorugh configuration file. `pdsch_AntennaPorts_N1` can be used to set N1 parameter, `pdsch_AntennaPorts_N2` to set N2 and `pdsch_AntennaPorts_XP` to set the cross-polarization configuration (1 for single pol, 2 for cross-pol). To be noted that if XP is 1 but N1 and/or N2 are larger than 1, this would result in a non-standard configuration and the PMI selected would be the identity matrix regardless of CSI report. The default value for each of these parameters is 1. + +# Additional links [Selecting an alternative ldpc implementation at run time](../openair1/PHY/CODING/DOC/LDPCImplementation.md) diff --git a/doc/images/mimo_antenna_ports.png b/doc/images/mimo_antenna_ports.png new file mode 100644 index 0000000000000000000000000000000000000000..ef91f4becc80fe6c09b55f202f9d8054368bd88c GIT binary patch literal 18753 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 = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP; + int num_pdsch_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP; + RC.nrmac[Mod_idP]->xp_pdsch_antenna_ports = pdsch_AntennaPorts.XP; config_common(Mod_idP, ssb_SubcarrierOffset, - RC.nrmac[Mod_idP]->pdsch_antenna_ports, + num_pdsch_antenna_ports, pusch_AntennaPorts, scc); LOG_D(NR_MAC, "%s() %s:%d RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index a3bf413b29..3db53ef809 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1183,7 +1183,7 @@ void nr_schedule_ue_spec(module_id_t module_id, nrOfLayers, csi_report->N1, csi_report->N2, - gNB_mac->pdsch_antenna_ports, + gNB_mac->xp_pdsch_antenna_ports, csi_report->codebook_mode); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1eb54ab45c..33390ec637 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -149,12 +149,13 @@ uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl) { uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int layers, int N1, int N2, - int config_file_ant_ports, + int xp_pdsch_antenna_ports, int codebook_mode) { int antenna_ports = (N1*N2)<<1; - if (antenna_ports!=config_file_ant_ports) - return 0; //identity matrix + if (xp_pdsch_antenna_ports == 1 && + antenna_ports>1) + return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas) int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1; int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 455538a361..7ab738b87c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -458,7 +458,7 @@ void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps); uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int layers, int N1, int N2, - int config_file_ant_ports, + int xp_pdsch_antenna_ports, int codebook_mode); void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 8b685fdd02..ecea3a2bd1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -806,7 +806,7 @@ typedef struct gNB_MAC_INST_s { uint16_t cset0_bwp_size; NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[64]; - int pdsch_antenna_ports; + int xp_pdsch_antenna_ports; bool first_MIB; double dl_bler_target_upper; From 07d20ba12196cf3680319d0fc3e12883d6fc2e9f Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 23 Mar 2022 09:58:55 +0100 Subject: [PATCH 056/226] fix for memory issues --- openair1/PHY/INIT/nr_init_ue.c | 17 ----------------- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 6 +++--- .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 4 ++-- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 19 +++++++++++-------- openair1/PHY/defs_nr_UE.h | 8 -------- 5 files changed, 16 insertions(+), 38 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index a68da3257c..6d3e88faf0 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -155,23 +155,6 @@ void phy_term_nr_ue__PDSCH(NR_UE_PDSCH* pdsch, const NR_DL_FRAME_PARMS *const fp free_and_zero(pdsch->dl_ch_ptrs_estimates_ext); } -void phy_init_nr_ue_PUSCH(NR_UE_PUSCH *const pusch, - const NR_DL_FRAME_PARMS *const fp) { - AssertFatal( pusch, "pusch==0" ); - - int max_encoded_length = fp->N_RB_UL*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8*NR_MAX_NB_LAYERS; - - for (int i=0; itxdataF_precoding[i] = (int32_t *)malloc16_clear((max_encoded_length)*sizeof(int32_t *)); - } -} - -void phy_term_nr_ue_PUSCH(NR_UE_PUSCH *pusch) -{ - for (int i = 0; i < NR_MAX_NB_LAYERS; i++) - free_and_zero(pusch->txdataF_precoding[i]); -} - int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) { // create shortcuts diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 7a76d0736c..33b4b8b17d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -110,9 +110,9 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL) ulsch->harq_processes[i] = (NR_UL_gNB_HARQ_t *)malloc16_clear(sizeof(NR_UL_gNB_HARQ_t)); ulsch->harq_processes[i]->b = (uint8_t*)malloc16_clear(ulsch_bytes); - ulsch->harq_processes[i]->c = (uint8_t**)malloc16_clear(a_segments); - ulsch->harq_processes[i]->d = (int16_t**)malloc16_clear(a_segments); - ulsch->harq_processes[i]->p_nrLDPC_procBuf = (t_nrLDPC_procBuf **)malloc16_clear(a_segments); + ulsch->harq_processes[i]->c = (uint8_t**)malloc16_clear(a_segments*sizeof(uint8_t *)); + ulsch->harq_processes[i]->d = (int16_t**)malloc16_clear(a_segments*sizeof(int16_t *)); + ulsch->harq_processes[i]->p_nrLDPC_procBuf = (t_nrLDPC_procBuf **)malloc16_clear(a_segments*sizeof(t_nrLDPC_procBuf *)); for (r=0; rharq_processes[i]->p_nrLDPC_procBuf[r] = nrLDPC_init_mem(); ulsch->harq_processes[i]->c[r] = (uint8_t*)malloc16_clear(8448*sizeof(uint8_t)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 0ee817ca77..30219875d9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -149,8 +149,8 @@ NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, NR_DL_ DevAssert(ulsch->harq_processes[i]->b); bzero(ulsch->harq_processes[i]->b,ulsch_bytes); - ulsch->harq_processes[i]->c = malloc16(a_segments); - ulsch->harq_processes[i]->d = malloc16(a_segments); + ulsch->harq_processes[i]->c = malloc16(a_segments*sizeof(uint8_t *)); + ulsch->harq_processes[i]->d = malloc16(a_segments*sizeof(uint16_t *)); for (int r = 0; r < a_segments; r++) { // account for filler in first segment and CRCs for multiple segment case ulsch->harq_processes[i]->c[r] = malloc16(8448); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index e8f2b51ee7..380487172f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -122,8 +122,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, int sample_offsetF, N_RE_prime; NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; - NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id]; - int16_t **tx_precoding = (int16_t **)pusch_ue->txdataF_precoding; int32_t **txdataF = UE->common_vars.txdataF; int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig @@ -333,13 +331,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, #endif } - else - memcpy(y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); - for (int nl = 0; nl < Nl; nl++) - free_and_zero(tx_layers[nl]); - free_and_zero(tx_layers); - /////////// //////////////////////////////////////////////////////////////////////// @@ -348,6 +340,10 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH RE mapping///////////////////////// /////////// + int encoded_length = frame_parms->N_RB_UL*number_of_symbols*NR_NB_SC_PER_RB*mod_order*Nl; + int16_t **tx_precoding = (int16_t **)malloc16_clear(Nl*sizeof(int16_t *)); + for (int nl=0; nlulsch[thread_id][gNB_id]->harq_processes[harq_pid]; harq_process_ulsch->status = SCH_IDLE; + for (int nl = 0; nl < Nl; nl++) { + free_and_zero(tx_layers[nl]); + free_and_zero(tx_precoding[nl]); + } + free_and_zero(tx_layers); + free_and_zero(tx_precoding); + /////////// //////////////////////////////////////////////////////////////////////// diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 7a8d680d70..04080e7215 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -225,11 +225,6 @@ typedef struct { } NR_UE_COMMON_PER_THREAD; -typedef struct { - /// TX buffers for UE-spec transmission - int32_t *txdataF_precoding[NR_MAX_NB_LAYERS]; - } NR_UE_PUSCH; - typedef struct { bool active[2]; fapi_nr_ul_config_pucch_pdu pucch_pdu[2]; @@ -793,9 +788,6 @@ typedef struct { NR_UE_DLSCH_t *dlsch_p[NUMBER_OF_CONNECTED_gNB_MAX]; NR_UE_DLSCH_t *dlsch_MCH[NUMBER_OF_CONNECTED_gNB_MAX]; - // to be removed again possibly - NR_UE_PUSCH *pusch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_gNB_MAX]; - //Paging parameters uint32_t IMSImod1024; uint32_t PF; From 3387a94ae3008c35b7c3e271cd9ef90b5200d762 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 23 Mar 2022 15:47:07 +0100 Subject: [PATCH 057/226] fix for fr2 sl_ahead --- .../conf_files/gnb.band261.tm1.32PRB.usrpn300.conf | 1 + openair1/PHY/NR_UE_TRANSPORT/nr_prach.c | 9 ++++++--- openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h | 2 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 ++-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf index e8c6cab1b4..0bb8346f6a 100644 --- a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf @@ -227,6 +227,7 @@ RUs = ( att_tx = 0; att_rx = 0; bands = [7]; + sl_ahead = 12; max_pdschReferenceSignalPower = -27; max_rxgain = 75; eNB_instances = [0]; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index 24299fd788..4927fe37a2 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -57,7 +57,7 @@ extern const char *prachfmt[]; // - idft for short sequence assumes we are transmitting starting in symbol 0 of a PRACH slot // - Assumes that PRACH SCS is same as PUSCH SCS @ 30 kHz, take values for formats 0-2 and adjust for others below // - Preamble index different from 0 is not detected by gNB -int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ +int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot){ NR_DL_FRAME_PARMS *fp=&ue->frame_parms; fapi_nr_config_request_t *nrUE_config = &ue->nrUE_config; @@ -190,8 +190,9 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ // now generate PRACH signal #ifdef NR_PRACH_DEBUG if (NCS>0) - LOG_I(PHY, "PRACH [UE %d] generate PRACH in slot %d for RootSeqIndex %d, Preamble Index %d, PRACH Format %s, NCS %d (N_ZC %d): Preamble_offset %d, Preamble_shift %d msg1 frequency start %d\n", + LOG_I(PHY, "PRACH [UE %d] generate PRACH in frame.slot %d.%d for RootSeqIndex %d, Preamble Index %d, PRACH Format %s, NCS %d (N_ZC %d): Preamble_offset %d, Preamble_shift %d msg1 frequency start %d\n", Mod_id, + frame, slot, rootSequenceIndex, preamble_index, @@ -221,7 +222,9 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ k += kbar; k *= 2; - LOG_I(PHY, "PRACH [UE %d] in slot %d, placing PRACH in position %d, msg1 frequency start %d (k1 %d), preamble_offset %d, first_nonzero_root_idx %d\n", Mod_id, + LOG_I(PHY, "PRACH [UE %d] in frame.slot %d.%d, placing PRACH in position %d, msg1 frequency start %d (k1 %d), preamble_offset %d, first_nonzero_root_idx %d\n", + Mod_id, + frame, slot, k, n_ra_prb, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index aac59a7da1..35e30d63bf 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -1704,7 +1704,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, unsigned char i_mod, unsigned char harq_pid); -int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t subframe); +int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot); void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid); /**@}*/ diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index ddddcd09e2..be229f68c3 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1801,7 +1801,7 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_IN); - prach_power = generate_nr_prach(ue, gNB_id, nr_slot_tx); + prach_power = generate_nr_prach(ue, gNB_id, frame_tx, nr_slot_tx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 670f337c31..a63419f8e9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -466,12 +466,12 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot, uint8_t start_next_period = (rach_slot-(rach_slot%tdd_period_slot)+tdd_period_slot)%nr_slots_per_frame[mu]; *msg2_slot = start_next_period + last_dl_slot_period; // initializing scheduling of slot to next mixed (or last dl) slot *msg2_frame = ((*msg2_slot>(rach_slot))? rach_frame : (rach_frame+1))%1024; - // we can't schedule msg2 before sl_ahead since prach int eff_slot = *msg2_slot+(*msg2_frame-rach_frame)*nr_slots_per_frame[mu]; - if ((eff_slot-rach_slot)<=sl_ahead) { + while ((eff_slot-rach_slot)<=sl_ahead) { *msg2_slot = (*msg2_slot+tdd_period_slot)%nr_slots_per_frame[mu]; *msg2_frame = ((*msg2_slot>(rach_slot))? rach_frame : (rach_frame+1))%1024; + eff_slot = *msg2_slot+(*msg2_frame-rach_frame)*nr_slots_per_frame[mu]; } if (FR==nr_FR2) { int num_tdd_period = *msg2_slot/tdd_period_slot; From d36549f80a988a880e65a071e4ebe2be6f393bfc Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 23 Mar 2022 19:15:02 +0100 Subject: [PATCH 058/226] fix memory issues --- cmake_targets/autotests/test_case_list.xml | 2 +- openair1/PHY/INIT/nr_init.c | 9 ++++++++- openair1/PHY/NR_TRANSPORT/nr_scrambling.c | 1 + openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 7 +++---- openair1/SIMULATION/NR_PHY/ulsim.c | 4 ++-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 36dbe9de07..5687810e69 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1324,7 +1324,7 @@ -n100 -s5 -T 2 1 2 -U 2 0 2 -n100 -s5 -T 2 2 2 -U 2 1 2 -n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3 - -n100 -s5 -Z + -n100 -Z -s5 -n100 -s5 -Z -r75 -n50 -s5 -Z -r216 -R217 -n50 -s5 -Z -r270 -R273 diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 131e74469e..8e698b09cd 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -285,7 +285,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (i=0; irxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); - pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear( NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); + pusch_vars[ULSCH_id]->rho[i] = (int32_t **)malloc16_clear(NR_MAX_NB_LAYERS*NR_MAX_NB_LAYERS*sizeof(int32_t*)); for (int j=0; j< max_ul_mimo_layers; j++) { for (int k=0; kpusch_vars; for (int ULSCH_id=0; ULSCH_idnumber_of_nr_ulsch_max; ULSCH_id++) { + for (int i=0; i< max_ul_mimo_layers; i++) + free_and_zero(pusch_vars[ULSCH_id]->llr_layers[i]); for (int i = 0; i < Prx; i++) { free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext[i]); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext2[i]); + for (int j=0; j< max_ul_mimo_layers; j++) { + for (int k=0; krho[i][j*max_ul_mimo_layers+k]); + } free_and_zero(pusch_vars[ULSCH_id]->rho[i]); } for (int i = 0; i < n_buf; i++) { @@ -434,6 +440,7 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb[i]); } + free_and_zero(pusch_vars[ULSCH_id]->llr_layers); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext2); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates); diff --git a/openair1/PHY/NR_TRANSPORT/nr_scrambling.c b/openair1/PHY/NR_TRANSPORT/nr_scrambling.c index 4bbecfd994..8a49a7ffe0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_scrambling.c +++ b/openair1/PHY/NR_TRANSPORT/nr_scrambling.c @@ -52,6 +52,7 @@ void nr_codeword_scrambling(uint8_t *in, ((uint16_t*)&in32)[0] = _mm_movemask_epi8(_mm_slli_epi16(in128[0],7)); ((uint16_t*)&in32)[1] = _mm_movemask_epi8(_mm_slli_epi16(in128[1],7)); out[i]=(in32^s); + LOG_D(PHY,"in[%d] %x => %x\n",i,in32,out[i]); s=lte_gold_generic(&x1, &x2, 0); } //#elsif defined(__arm__) || defined(__aarch64) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 30219875d9..1acb722ecd 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -318,7 +318,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, printf("start ldpc encoder segment %d/%d\n",r,harq_process->C); printf("input %d %d %d %d %d \n", harq_process->c[r][0], harq_process->c[r][1], harq_process->c[r][2],harq_process->c[r][3], harq_process->c[r][4]); for (int cnt =0 ; cnt < 22*(*pz)/8; cnt ++){ - printf("%d ", harq_process->c[r][cnt]); + printf("%d ", harq_process->c[r][cnt]); } printf("\n"); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 380487172f..740299477b 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -114,7 +114,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); - uint32_t available_bits; int8_t Wf[2], Wt[2]; int l_prime[2], delta; uint8_t nb_dmrs_re_per_rb; @@ -183,7 +182,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH scrambling///////////////////////// /////////// - available_bits = G; + uint32_t available_bits = G; uint32_t scrambled_output[(available_bits>>5)+1]; memset(scrambled_output, 0, ((available_bits>>5)+1)*sizeof(uint32_t)); @@ -200,7 +199,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH modulation///////////////////////// /////////// - int max_num_re = number_of_symbols*nb_rb*NR_NB_SC_PER_RB; + int max_num_re = Nl*number_of_symbols*nb_rb*NR_NB_SC_PER_RB; int32_t d_mod[max_num_re] __attribute__ ((aligned(16))); nr_modulation(scrambled_output, // assume one codeword for the moment @@ -340,7 +339,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH RE mapping///////////////////////// /////////// - int encoded_length = frame_parms->N_RB_UL*number_of_symbols*NR_NB_SC_PER_RB*mod_order*Nl; + int encoded_length = frame_parms->N_RB_UL*14*NR_NB_SC_PER_RB*mod_order*Nl; int16_t **tx_precoding = (int16_t **)malloc16_clear(Nl*sizeof(int16_t *)); for (int nl=0; nlul_dmrs_symb_pos); ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymPos, pusch_pdu->start_symbol_index, pusch_pdu->nr_of_symbols); ptrsRePerSymb = ((pusch_pdu->rb_size + ptrs_freq_density - 1)/ptrs_freq_density); - printf("[ULSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot,ptrsRePerSymb, ptrsSymbPerSlot*ptrsRePerSymb ); + LOG_D(PHY,"[ULSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot,ptrsRePerSymb, ptrsSymbPerSlot*ptrsRePerSymb ); } //////////////////////////////////////////////////////////// From ed1c87b59816b3979146f5d33bd33f0f6d597a1f Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 14 Mar 2022 17:53:57 +0100 Subject: [PATCH 059/226] commit before rebase --- cmake_targets/phy_simulators | 1 - common/utils/lte/ue_power.c | 6 +- executables/nr-uesoftmodem.c | 9 +- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 23 ++--- openair1/PHY/NR_TRANSPORT/nr_dci.c | 2 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 92 +++++++++++-------- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 9 +- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 8 +- openair1/PHY/TOOLS/dB_routines.h | 35 ------- openair1/PHY/TOOLS/tools_defs.h | 22 +++-- openair1/SCHED/sched_common_vars.h | 1 + openair1/SCHED_NR_UE/harq_nr.c | 64 ++++--------- openair2/LAYER2/MAC/config.c | 5 - openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 3 +- openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 24 ++--- targets/RT/USER/lte-ue.c | 12 +-- 17 files changed, 125 insertions(+), 192 deletions(-) delete mode 120000 cmake_targets/phy_simulators delete mode 100644 openair1/PHY/TOOLS/dB_routines.h diff --git a/cmake_targets/phy_simulators b/cmake_targets/phy_simulators deleted file mode 120000 index 2a12e92f3e..0000000000 --- a/cmake_targets/phy_simulators +++ /dev/null @@ -1 +0,0 @@ -ran_build/ \ No newline at end of file diff --git a/common/utils/lte/ue_power.c b/common/utils/lte/ue_power.c index b377abf2ff..aaa2826275 100644 --- a/common/utils/lte/ue_power.c +++ b/common/utils/lte/ue_power.c @@ -33,10 +33,8 @@ #include #include #include "PHY/defs_eNB.h" -#include "PHY/TOOLS/dB_routines.h" - -extern int16_t hundred_times_delta_TF[100]; -extern uint16_t hundred_times_log10_NPRB[100]; +#include +#include int16_t estimate_ue_tx_power(int norm,uint32_t tbs, uint32_t nb_rb, uint8_t control_only, int ncp, uint8_t use_srs) { diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 76c21bb422..649b68631b 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -241,14 +241,17 @@ nrUE_params_t *get_nrUE_params(void) { } /* initialie thread pools used for NRUE processing paralleliation */ void init_tpools(uint8_t nun_dlsch_threads) { - char *params = NULL; - params = calloc(1,(NR_RX_NB_TH*NR_NB_TH_SLOT*3)+1); + char params[NR_RX_NB_TH*NR_NB_TH_SLOT*3+1]; for (int i=0; iframe_parms; NR_gNB_COMMON *common_vars = &gNB->common_vars; PHY_MEASUREMENTS_gNB *measurements = &gNB->measurements; - int rb, offset, offset0, nb_symb[275], len; - int32_t *ul_ch; - - LOG_D(PHY,"slot %d Doing I0 for first_symb %d, num_symb %d\n",slot,first_symb,num_symb); + int rb, nb_symb[275]={0}; + + memset(measurements->n0_subband_power, 0, sizeof(measurements->n0_subband_power)); + for (int s=first_symb;s<(first_symb+num_symb);s++) { for (rb=0; rbN_RB_UL; rb++) { - - if (s==first_symb) { - nb_symb[rb]=0; - for (int aarx=0; aarxnb_antennas_rx;aarx++) - measurements->n0_subband_power[aarx][rb]=0; - } - offset0 = (slot&3)*(frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size) + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; + int offset0 = (slot&3)*(frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size) + + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; if ((gNB->rb_mask_ul[s][rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe nb_symb[rb]++; for (int aarx=0; aarxnb_antennas_rx; aarx++) { - offset = offset0 + (s*frame_parms->ofdm_symbol_size); - ul_ch = &common_vars->rxdataF[aarx][offset]; - len = 12; + int offset = offset0 + (s*frame_parms->ofdm_symbol_size); + int32_t *ul_ch = &common_vars->rxdataF[aarx][offset]; + int len = 12; if (((frame_parms->N_RB_UL&1) == 1) && (rb==(frame_parms->N_RB_UL>>1))) { len=6; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 0af56ba706..ae96eb26bc 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -132,7 +132,7 @@ void nr_generate_dci(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, polar_encoder_fast((uint64_t*)dci_pdu->Payload, (void*)encoder_output, n_RNTI, 1, NR_POLAR_DCI_MESSAGE_TYPE, dci_pdu->PayloadSizeBits, dci_pdu->AggregationLevel); -#ifdef DEBUG_CHANNEL_CODING +#if 1 printf("polar rnti %x,length %d, L %d\n",n_RNTI, dci_pdu->PayloadSizeBits,pdcch_pdu_rel15->dci_pdu->AggregationLevel); printf("DCI PDU: [0]->0x%lx \t [1]->0x%lx\n", ((uint64_t*)dci_pdu->Payload)[0], ((uint64_t*)dci_pdu->Payload)[1]); diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 50c3b62f50..17f145b98a 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -243,7 +243,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, * x(l*12+n) = r_u_v_alpha_delta(n) */ // the value of u,v (delta always 0 for PUCCH) has to be calculated according to TS 38.211 Subclause 6.3.2.2.1 - uint8_t u[2]={0,0},v[2]={0,0}; + uint8_t u[2]={0},v[2]={0}; // x_n contains the sequence r_u_v_alpha_delta(n) @@ -262,7 +262,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, AssertFatal(pucch_pdu->nr_of_symbols < 3,"nr_of_symbols %d not allowed\n",pucch_pdu->nr_of_symbols); - uint32_t re_offset[2]={0,0}; + uint32_t re_offset[2]={0}; uint8_t l2; const int16_t *x_re[2],*x_im[2]; @@ -271,16 +271,11 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, x_re[1] = table_5_2_2_2_2_Re[u[1]]; x_im[1] = table_5_2_2_2_2_Im[u[1]]; - int16_t xr[1+frame_parms->nb_antennas_rx][1+pucch_pdu->nr_of_symbols][24] __attribute__((aligned(32))); + c64_t xr[frame_parms->nb_antennas_rx][pucch_pdu->nr_of_symbols][12] __attribute__((aligned(32))); + memset(xr, 0, sizeof(xr)); int64_t xrtmag=0,xrtmag_next=0; uint8_t maxpos=0; uint8_t index=0; - for (int l=0; lnr_of_symbols; l++) { - for (int aarx=0;aarxnb_antennas_rx;aarx++) { - memset((void*)xr[aarx][l],0,24*sizeof(int16_t)); - } - } - int n2; for (int l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; @@ -289,23 +284,23 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, re_offset[l]-=frame_parms->ofdm_symbol_size; AssertFatal(re_offset[l]+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n"); - int16_t *r; for (int aa=0;aanb_antennas_rx;aa++) { - r=(int16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; - n2=0; - for (n=0;n<12;n++,n2+=2) { - xr[aa][l][n2] +=(int16_t)(((int32_t)x_re[l][n]*r[n2]+(int32_t)x_im[l][n]*r[n2+1])>>15); - xr[aa][l][n2+1]+=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); + c16_t *r=(c16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; + for (n=0;n<12;n++) { + xr[aa][l][n].r +=(int32_t)x_re[l][n]*r[n].r+(int32_t)x_im[l][n]*r[n].i; + xr[aa][l][n].i +=(int32_t)x_re[l][n]*r[n].i-(int32_t)x_im[l][n]*r[n].r; #ifdef DEBUG_NR_PUCCH_RX - printf("x (%d,%d), r%d.%d (%d,%d), xr (%d,%d)\n", - x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); + printf("x (%d,%d), r%d.%d (%d,%d), xr (%lld,%lld)\n", + x_re[l][n],x_im[l][n],l2,re_offset[l],r[n].r,r[n].i,xr[aa][l][n].r,xr[aa][l][n].i); #endif } + xr[aa][l][n].r>>=15; + xr[aa][l][n].i>>=15; } } - int32_t corr_re[1+frame_parms->nb_antennas_rx][2]; - int32_t corr_im[1+frame_parms->nb_antennas_rx][2]; + int64_t corr_re[frame_parms->nb_antennas_rx][2]; + int64_t corr_im[frame_parms->nb_antennas_rx][2]; //int32_t no_corr = 0; int seq_index = 0; int64_t temp; @@ -322,19 +317,19 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (int aa=0;aanb_antennas_rx;aa++) { corr_re[aa][l]=0; corr_im[aa][l]=0; - - n2=0; - for (n=0;n<12;n++,n2+=2) { - corr_re[aa][l]+=(xr[aa][l][n2]*idft12_re[seq_index][n]+xr[aa][l][n2+1]*idft12_im[seq_index][n])>>15; - corr_im[aa][l]+=(xr[aa][l][n2]*idft12_im[seq_index][n]-xr[aa][l][n2+1]*idft12_re[seq_index][n])>>15; + for (n=0;n<12;n++) { + corr_re[aa][l]+=xr[aa][l][n].r*idft12_re[seq_index][n]+xr[aa][l][n].i*idft12_im[seq_index][n]; + corr_im[aa][l]+=xr[aa][l][n].r*idft12_im[seq_index][n]-xr[aa][l][n].i*idft12_re[seq_index][n]; } + corr_re[aa][l]>>=15; + corr_im[aa][l]>>=15; } } - LOG_D(PHY,"PUCCH IDFT[%d/%d] = (%d,%d)=>%f\n", + LOG_D(PHY,"PUCCH IDFT[%d/%d] = (%ld,%ld)=>%f\n", mcs[i],seq_index,corr_re[0][0],corr_im[0][0], 10*log10((double)corr_re[0][0]*corr_re[0][0] + (double)corr_im[0][0]*corr_im[0][0])); if (pucch_pdu->nr_of_symbols==2) - LOG_D(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%d,%d)=>%f\n", + LOG_D(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%ld,%ld)=>%f\n", mcs[i],seq_index,corr_re[0][1],corr_im[0][1], 10*log10((double)corr_re[0][1]*corr_re[0][1] + (double)corr_im[0][1]*corr_im[0][1])); if (pucch_pdu->freq_hop_flag == 0) { @@ -392,7 +387,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; LOG_D(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); // estimate CQI for MAC (from antenna port 0 only) - int max_n0 = uci_stats->pucch0_n00>uci_stats->pucch0_n01 ? uci_stats->pucch0_n00:uci_stats->pucch0_n01; + int max_n0 = max(gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]], + gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]); int SNRtimes10,sigenergy=0; for (int aa=0;aanb_antennas_rx;aa++) sigenergy += signal_energy_nodc(&rxdataF[aa][soffset+ @@ -407,8 +403,16 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->pucch0_thres = gNB->pucch0_thres; /* + (10*max_n0);*/ bool no_conf=false; if (nr_sequences>1) { - if (xrtmag_dBtimes10 < (50+xrtmag_next_dBtimes10) || SNRtimes10 < uci_stats->pucch0_thres) + if (xrtmag_dBtimes10 < (50+xrtmag_next_dBtimes10) || SNRtimes10 < gNB->pucch0_thres) { no_conf=true; + LOG_W(PHY,"%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n", + frame, slot, + uci_stats->pucch0_thres, + SNRtimes10, + xrtmag_dBtimes10, + xrtmag_next_dBtimes10); + abort(); + } } gNB->bad_pucch += no_conf; // first bit of bitmap for sr presence and second bit for acknack presence @@ -422,7 +426,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, if (pucch_pdu->bit_len_harq==0) { uci_pdu->harq = NULL; uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); - uci_pdu->sr->sr_confidence_level = no_conf ? 1 : 0; + uci_pdu->sr->sr_confidence_level = no_conf; uci_stats->pucch0_sr_trials++; if (xrtmag_dBtimes10>(10*gNB->measurements.n0_power_tot_dB)) { uci_pdu->sr->sr_indication = 1; @@ -434,17 +438,19 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, else if (pucch_pdu->bit_len_harq==1) { uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); uci_pdu->harq->num_harq = 1; - uci_pdu->harq->harq_confidence_level = no_conf ? 1 : 0; - uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); + uci_pdu->harq->harq_confidence_level = no_conf; + uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(sizeof *uci_pdu->harq->harq_list); uci_pdu->harq->harq_list[0].harq_value = !(index&0x01); - LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad) xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", - frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ %s with confidence level %s xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + frame,slot,uci_pdu->harq->harq_list[0].harq_value==0?"ACK":"NACK", + uci_pdu->harq->harq_confidence_level==0?"good":"bad", + xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); - uci_pdu->sr->sr_indication = (index>1) ? 1 : 0; - uci_pdu->sr->sr_confidence_level = no_conf ? 1 : 0; + uci_pdu->sr->sr_indication = (index>1); + uci_pdu->sr->sr_confidence_level = no_conf; uci_stats->pucch0_positive_SR++; } uci_stats->pucch01_trials++; @@ -452,17 +458,23 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, else { uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); uci_pdu->harq->num_harq = 2; - uci_pdu->harq->harq_confidence_level = (no_conf) ? 1 : 0; - uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2); + uci_pdu->harq->harq_confidence_level = no_conf; + uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2 * sizeof( *uci_pdu->harq->harq_list)); uci_pdu->harq->harq_list[1].harq_value = !(index&0x01); uci_pdu->harq->harq_list[0].harq_value = !((index>>1)&0x01); - LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d and %d (0 pass, 1 fail) with confidence level %d (0 is good, 1 is bad), xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", - frame,slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,gNB->ulsch_stats[0].sync_pos); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values (%s, %s) with confidence level %s, xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", + frame,slot, + uci_pdu->harq->harq_list[1].harq_value == 0 ? "ACK" : "NACK", + uci_pdu->harq->harq_list[0].harq_value == 0 ? "ACK" : "NACK", + uci_pdu->harq->harq_confidence_level == 0 ? "good" : "bad", + xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0, + uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi, + SNRtimes10,gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_indication = (index>3) ? 1 : 0; - uci_pdu->sr->sr_confidence_level = (no_conf) ? 1 : 0; + uci_pdu->sr->sr_confidence_level = no_conf; } } } diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 5e18f6cc6d..9f0e1bea71 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -817,6 +817,10 @@ void nr_pdcch_unscrambling(int16_t *z, if (((s >> (i % 32)) & 1) == 1) z2[i] = -z[i]; else z2[i]=z[i]; } + printf("Encoded Payload (length:%d dwords):\n", length>>5); + + for (int i=0; i>5; i++) + printf("[%d]->0x%08x \t", i, z2[i]); } @@ -868,6 +872,7 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, int L = rel15->L[j]; // Loop over possible DCI lengths + for (int k = 0; k < rel15->num_dci_options; k++) { // skip this candidate if we've already found one with the // same rnti and format at a different aggregation level @@ -902,8 +907,8 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, NR_POLAR_DCI_MESSAGE_TYPE, dci_length, L); n_rnti = rel15->rnti; - LOG_D(PHY, "(%i.%i) dci indication (rnti %x,dci format %s,n_CCE %d,payloadSize %d)\n", - proc->frame_rx, proc->nr_slot_rx,n_rnti,nr_dci_format_string[rel15->dci_format_options[k]],CCEind,dci_length); + LOG_D(PHY, "(%i.%i) dci indication (rnti %x,dci format %s,n_CCE %d,payloadSize %d,payload %llx )\n", + proc->frame_rx, proc->nr_slot_rx,n_rnti,nr_dci_format_string[rel15->dci_format_options[k]],CCEind,dci_length, *(unsigned long long*)dci_estimation); if (crc == n_rnti) { LOG_D(PHY, "(%i.%i) Received dci indication (rnti %x,dci format %s,n_CCE %d,payloadSize %d,payload %llx)\n", proc->frame_rx, proc->nr_slot_rx,n_rnti,nr_dci_format_string[rel15->dci_format_options[k]],CCEind,dci_length,*(unsigned long long*)dci_estimation); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 54b7c34608..bf9cfaaa70 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -172,6 +172,7 @@ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint memset(dlsch->harq_processes[i]->d[r],0,5*8448); else exit_flag=2; + } } else { exit_flag=1; @@ -299,17 +300,14 @@ void nr_processDLSegment(void* arg) { K_bits_F = Kr-harq_process->F; t_nrLDPC_time_stats procTime = {0}; - t_nrLDPC_time_stats* p_procTime = &procTime ; t_nrLDPC_procBuf **p_nrLDPC_procBuf = harq_process->p_nrLDPC_procBuf; - int16_t w[5*8448]; - memset(w,0,(5*8448)*sizeof(short)); - start_meas(&rdata->ts_deinterleave); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); + int16_t w[E]; nr_deinterleaving_ldpc(E, Qm, w, // [hna] w is e @@ -397,7 +395,7 @@ void nr_processDLSegment(void* arg) { (int8_t *)&pl[0], llrProcBuf, p_nrLDPC_procBuf[r], - p_procTime); + &procTime); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_OUT); // Fixme: correct type is unsigned, but nrLDPC_decoder and all called behind use signed int diff --git a/openair1/PHY/TOOLS/dB_routines.h b/openair1/PHY/TOOLS/dB_routines.h deleted file mode 100644 index 185913cf5b..0000000000 --- a/openair1/PHY/TOOLS/dB_routines.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/* - * dB_routines.h - * - * Created on: Nov 12, 2013 - * Author: winckel - */ - -#ifndef DB_ROUTINES_H_ -#define DB_ROUTINES_H_ - -int16_t dB_fixed_times10(uint32_t x); -int16_t dB_fixed_x10(uint32_t x); - -#endif /* DB_ROUTINES_H_ */ diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 966e93440e..13ce9d85c7 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -39,26 +39,30 @@ extern "C" { #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) -struct complexd { +typedef struct complexd { double r; double i; -}; +} cd_t; -struct complexf { +typedef struct complexf { float r; float i; -}; +} cf_t; -struct complex16 { +typedef struct complex16 { int16_t r; int16_t i; -}; +} c16_t; -struct complex32 { +typedef struct complex32 { int32_t r; int32_t i; -}; - +} c32_t; + +typedef struct complex64 { + int64_t r; + int64_t i; +} c64_t; //cmult_sv.h /*!\fn void multadd_real_vector_complex_scalar(int16_t *x,int16_t *alpha,int16_t *y,uint32_t N) diff --git a/openair1/SCHED/sched_common_vars.h b/openair1/SCHED/sched_common_vars.h index 2cae2aa96f..8886e0d576 100644 --- a/openair1/SCHED/sched_common_vars.h +++ b/openair1/SCHED/sched_common_vars.h @@ -20,6 +20,7 @@ */ #include +#include // This is the formula from Section 5.1.1.1 in 36.213 100*10*log10((2^(MPR*Ks)-1)), where MPR is in the range [0,6] and Ks=1.25 diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index 4afe5f41d3..6508e2568e 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -339,55 +339,23 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int dl_harq->first_rx = 1; } else{ - switch(rv){ - case 0: - dl_harq->round = 0; + LOG_D(PHY,"receive harq process: %p harqPid=%d, rv=%d, ndi=%d, rntiType=%d, DCIndi=%d\n", + dl_harq, harq_pid, rv, ndi, rnti_type, dl_harq->DCINdi); + AssertFatal(rv<4 && rv>=0, "invalid redondancy version %d\n", rv); + if (rv!=0 && dl_harq->ack == DL_NACK) + LOG_D(PHY,"New transmission on a harq pid (%d) never acknowledged\n", harq_pid); + if (rv==0 && ndi == dl_harq->DCINdi ) + LOG_D(PHY,"Missed previous DCI detections. redondancy version is new transmission, but ndi doesn't toogle\n"); + dl_harq->first_rx = (rv==0); + const int rounds[4]={0,3,1,2}; + dl_harq->round = rounds[rv]; dl_harq->status = ACTIVE; - dl_harq->first_rx = 1; - if (dl_harq->DCINdi == ndi) - LOG_E(PHY,"Warning! rv %d indicates new transmission but new ndi %d is the same as old ndi %d\n",rv,ndi,dl_harq->DCINdi); + if (rv!=0 && dl_harq->DCINdi != ndi ) + LOG_E(PHY,"Missed previous DCI detections. redondancy version (%d) is retransmission, but ndi toogle\n", rv); + if (rv!=0 && dl_harq->ack != DL_NACK) + LOG_E(PHY,"Missed previous DCI detections. redondancy version (%d) is retransmission, but status is not DL_NACK\n", rv); dl_harq->DCINdi = ndi; - break; - case 1: - dl_harq->round = 3; - dl_harq->status = ACTIVE; - dl_harq->first_rx = 0; - if (dl_harq->DCINdi != ndi) { - LOG_E(PHY,"Missed previous DCI detections. NDI toggled but rv %d does not correspond to first reception\n",rv); - dl_harq->first_rx = 1; - dl_harq->DCINdi = ndi; - } - else if (dl_harq->ack == 1) - dl_harq->status = SCH_IDLE; - break; - case 2: - dl_harq->round = 1; - dl_harq->status = ACTIVE; - dl_harq->first_rx = 0; - if (dl_harq->DCINdi != ndi) { - LOG_E(PHY,"Missed previous DCI detections. NDI toggled but rv %d does not correspond to first reception\n",rv); - dl_harq->first_rx = 1; - dl_harq->DCINdi = ndi; - } - else if (dl_harq->ack == 1) - dl_harq->status = SCH_IDLE; - break; - case 3: - dl_harq->round = 2; - dl_harq->status = ACTIVE; - dl_harq->first_rx = 0; - if (dl_harq->DCINdi != ndi) { - LOG_E(PHY,"Missed previous DCI detections. NDI toggled but rv %d does not correspond to first reception\n",rv); - dl_harq->first_rx = 1; - dl_harq->DCINdi = ndi; - } - else if (dl_harq->ack == 1) - dl_harq->status = SCH_IDLE; - break; - default: - AssertFatal(1==0,"Invalid value for rv %d\n",rv); - } - } - + //dl_harq->status = SCH_IDLE; + } } diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 209275acb3..d22485d23f 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -58,11 +58,6 @@ extern int l2_init_eNB(void); extern void mac_top_init_eNB(void); extern void mac_init_cell_params(int Mod_idP,int CC_idP); - -int32_t **rxdata; -int32_t **txdata; - - typedef struct eutra_bandentry_s { int16_t band; uint32_t ul_min; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index c57736990c..0c339ee70a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2092,6 +2092,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, pucch->is_common = current_harq->is_common; current_harq->active = false; current_harq->ack_received = false; + LOG_D(PHY,"%d.%d Sent %d ack on harq pid %d\n", frame, slot, current_harq->ack, dl_harq_pid); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index cedc78097e..fad5643370 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -811,6 +811,7 @@ static void handle_dl_harq(module_id_t mod_id, stats->dlsch_errors++; LOG_D(NR_MAC, "retransmission error for UE %d (total %"PRIu64")\n", UE_id, stats->dlsch_errors); } else { + LOG_D(PHY,"NACK for: pid %d, ue %x\n",harq_pid, UE_id); add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].retrans_dl_harq, harq_pid); harq->round++; } @@ -1442,7 +1443,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, DevAssert(harq->is_waiting); const int8_t pid = sched_ctrl->feedback_dl_harq.head; remove_front_nr_list(&sched_ctrl->feedback_dl_harq); - LOG_D(NR_MAC,"bit %d pid %d ack/nack %d\n",harq_bit,pid,harq_value); + LOG_D(NR_MAC,"%d.%d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value); handle_dl_harq(mod_id, UE_id, pid, harq_value == 0 && harq_confidence == 0); if (harq_confidence == 1) UE_info->mac_stats[UE_id].pucch0_DTX++; } diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index f7323010cb..99897f9060 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -78,13 +78,13 @@ void nrue_init_standalone_socket(int tx_port, int rx_port) int sd = socket(server_address.sin_family, SOCK_DGRAM, 0); if (sd < 0) { - LOG_E(MAC, "Socket creation error standalone PNF\n"); + LOG_E(NR_MAC, "Socket creation error standalone PNF\n"); return; } if (inet_pton(server_address.sin_family, stub_eth_params.remote_addr, &server_address.sin_addr) <= 0) { - LOG_E(MAC, "Invalid standalone PNF Address\n"); + LOG_E(NR_MAC, "Invalid standalone PNF Address\n"); close(sd); return; } @@ -92,7 +92,7 @@ void nrue_init_standalone_socket(int tx_port, int rx_port) // Using connect to use send() instead of sendto() if (connect(sd, (struct sockaddr *)&server_address, addr_len) < 0) { - LOG_E(MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); + LOG_E(NR_MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); close(sd); return; } @@ -118,7 +118,7 @@ void nrue_init_standalone_socket(int tx_port, int rx_port) if (bind(sd, (struct sockaddr *)&server_address, addr_len) < 0) { - LOG_E(MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); + LOG_E(NR_MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); close(sd); return; } @@ -603,10 +603,6 @@ static void copy_ul_tti_data_req_to_dl_info(nr_downlink_indication_t *dl_info, n pdu_0_1->harq->num_harq = 1; pdu_0_1->harq->harq_confidence_level = 0; pdu_0_1->harq->harq_list = CALLOC(pdu_0_1->harq->num_harq, sizeof(*pdu_0_1->harq->harq_list)); - for (int k = 0; k < pdu_0_1->harq->num_harq; k++) - { - pdu_0_1->harq->harq_list[k].harq_value = 0; - } } } LOG_I(NR_MAC, "We have dequeued the previously filled uci_ind and updated the snf/slot to %d/%d.\n", @@ -986,7 +982,7 @@ void *nrue_standalone_pnf_task(void *context) if (sem_post(&sfn_slot_semaphore) != 0) { - LOG_E(MAC, "sem_post() error\n"); + LOG_E(NR_MAC, "sem_post() error\n"); abort(); } } @@ -1062,7 +1058,7 @@ void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nac } else { //shouldn't get here - LOG_E(MAC, "Trying to process acknack for an inactive harq process (%d)\n", harq_pid); + LOG_E(NR_MAC, "Trying to process acknack for an inactive harq process (%d)\n", harq_pid); } } @@ -1121,9 +1117,9 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_ } else { // UL indication after reception of DCI or DL PDU if (dl_info && dl_info->dci_ind && dl_info->dci_ind->number_of_dcis) { - LOG_D(MAC,"[L2][IF MODULE][DL INDICATION][DCI_IND]\n"); + LOG_D(NR_MAC,"[L2][IF MODULE][DL INDICATION][DCI_IND]\n"); for (int i = 0; i < dl_info->dci_ind->number_of_dcis; i++) { - LOG_D(MAC,">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d\n",i,dl_info->dci_ind->number_of_dcis); + LOG_D(NR_MAC,">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d\n",i,dl_info->dci_ind->number_of_dcis); nr_scheduled_response_t scheduled_response; int8_t ret = handle_dci(dl_info->module_id, dl_info->cc_id, @@ -1137,7 +1133,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_ /* The check below filters out UL_DCIs (format 7) which are being processed as DL_DCIs. */ if (dci_index->dci_format == 7 && mac->ra.ra_state == RA_SUCCEEDED) { LOG_D(NR_MAC, "We are filtering a UL_DCI to prevent it from being treated like a DL_DCI\n"); - break; + continue; } dci_pdu_rel15_t *def_dci_pdu_rel15 = &mac->def_dci_pdu_rel15[dci_index->dci_format]; g_harq_pid = def_dci_pdu_rel15->harq_pid; @@ -1160,7 +1156,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_ for (int i=0; irx_ind->number_pdus; ++i) { - LOG_D(MAC, "In %s sending DL indication to MAC. 1 PDU type %d of %d total number of PDUs \n", + LOG_D(NR_MAC, "In %s sending DL indication to MAC. 1 PDU type %d of %d total number of PDUs \n", __FUNCTION__, dl_info->rx_ind->rx_indication_body[i].pdu_type, dl_info->rx_ind->number_pdus); diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 25da395b90..13a09db5a3 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -93,9 +93,6 @@ extern uint16_t sf_ahead; void ue_stub_rx_handler(unsigned int, char *); -int32_t **rxdata; -int32_t **txdata; - int timer_subframe = 0; int timer_frame = 0; SF_ticking *phy_stub_ticking = NULL; @@ -2498,23 +2495,18 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, AssertFatal( phy_vars_ue[CC_id] !=0, ""); frame_parms = &(phy_vars_ue[CC_id]->frame_parms); // replace RX signal buffers with mmaped HW versions - rxdata = (int32_t **)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t *) ); - txdata = (int32_t **)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t *) ); - for (i=0; inb_antennas_rx; i++) { LOG_I(PHY, "Mapping UE CC_id %d, rx_ant %d, freq %lu on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], phy_vars_ue[CC_id]->rf_map.card, (phy_vars_ue[CC_id]->rf_map.chain)+i ); free( phy_vars_ue[CC_id]->common_vars.rxdata[i] ); - rxdata[i] = (int32_t *)malloc16_clear( 307200*sizeof(int32_t) ); - phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD + phy_vars_ue[CC_id]->common_vars.rxdata[i] = malloc16_clear( 307200*sizeof(int32_t) ); // what about the "-N_TA_offset" ? // N_TA offset for TDD } for (i=0; inb_antennas_tx; i++) { LOG_I(PHY, "Mapping UE CC_id %d, tx_ant %d, freq %lu on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], phy_vars_ue[CC_id]->rf_map.card, (phy_vars_ue[CC_id]->rf_map.chain)+i ); free( phy_vars_ue[CC_id]->common_vars.txdata[i] ); - txdata[i] = (int32_t *)malloc16_clear( 307200*sizeof(int32_t) ); - phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i]; + phy_vars_ue[CC_id]->common_vars.txdata[i] = malloc16_clear( 307200*sizeof(int32_t) ); } // rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x] From 42c16795454fdaaed2617ac32e4eada3ec71318f Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 15 Mar 2022 14:23:25 +0100 Subject: [PATCH 060/226] remove one global --- openair1/PHY/INIT/nr_init_ue.c | 2 -- openair1/PHY/NR_TRANSPORT/nr_dci.c | 3 +- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 28 +++++++++++-------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 7 +++-- openair1/PHY/defs_nr_UE.h | 3 -- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 5 ++-- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 75315187d9..5a3c2569da 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -404,7 +404,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ue->pdcch_vars[th_id][gNB_id]->llr = (int16_t *)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); ue->pdcch_vars[th_id][gNB_id]->llr16 = (int16_t *)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); ue->pdcch_vars[th_id][gNB_id]->wbar = (int16_t *)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - ue->pdcch_vars[th_id][gNB_id]->e_rx = (int16_t *)malloc16_clear( 4*2*100*12 ); ue->pdcch_vars[th_id][gNB_id]->rxdataF_comp = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) ); ue->pdcch_vars[th_id][gNB_id]->dl_ch_rho_ext = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) ); ue->pdcch_vars[th_id][gNB_id]->rho = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); @@ -574,7 +573,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->pdcch_vars[th_id][gNB_id]->llr); free_and_zero(ue->pdcch_vars[th_id][gNB_id]->llr16); free_and_zero(ue->pdcch_vars[th_id][gNB_id]->wbar); - free_and_zero(ue->pdcch_vars[th_id][gNB_id]->e_rx); free_and_zero(ue->pdcch_vars[th_id][gNB_id]->rxdataF_comp); free_and_zero(ue->pdcch_vars[th_id][gNB_id]->dl_ch_rho_ext); free_and_zero(ue->pdcch_vars[th_id][gNB_id]->rho); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index ae96eb26bc..9876dfca86 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -132,7 +132,8 @@ void nr_generate_dci(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, polar_encoder_fast((uint64_t*)dci_pdu->Payload, (void*)encoder_output, n_RNTI, 1, NR_POLAR_DCI_MESSAGE_TYPE, dci_pdu->PayloadSizeBits, dci_pdu->AggregationLevel); -#if 1 +#ifdef DEBUG_CHANNEL_CODING +//debug dump dci printf("polar rnti %x,length %d, L %d\n",n_RNTI, dci_pdu->PayloadSizeBits,pdcch_pdu_rel15->dci_pdu->AggregationLevel); printf("DCI PDU: [0]->0x%lx \t [1]->0x%lx\n", ((uint64_t*)dci_pdu->Payload)[0], ((uint64_t*)dci_pdu->Payload)[1]); diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 9f0e1bea71..66422a9dfa 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -83,7 +83,7 @@ char nr_dci_format_string[8][30] = { //static const int16_t conjugate[8]__attribute__((aligned(32))) = {-1,1,-1,1,-1,1,-1,1}; -void nr_pdcch_demapping_deinterleaving(uint32_t *llr, +static void nr_pdcch_demapping_deinterleaving(uint32_t *llr, uint32_t *z, uint8_t coreset_time_dur, uint8_t start_symbol, @@ -685,7 +685,8 @@ void nr_pdcch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15) { + fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, + int16_t e_rx[4*2*100*12] ) { uint32_t frame = proc->frame_rx; uint32_t slot = proc->nr_slot_rx; @@ -772,7 +773,7 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, LOG_D(PHY,"we enter nr_pdcch_demapping_deinterleaving(), number of candidates %d\n",rel15->number_of_candidates); nr_pdcch_demapping_deinterleaving((uint32_t *) pdcch_vars->llr, - (uint32_t *) pdcch_vars->e_rx, + (uint32_t *) e_rx, rel15->coreset.duration, rel15->coreset.StartSymbolIndex, n_rb, @@ -791,7 +792,7 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, -void nr_pdcch_unscrambling(int16_t *z, +void nr_pdcch_unscrambling(int16_t e_rx[4*2*100*12], uint16_t scrambling_RNTI, uint32_t length, uint16_t pdcch_DMRS_scrambling_id, @@ -814,13 +815,15 @@ void nr_pdcch_unscrambling(int16_t *z, reset = 0; } - if (((s >> (i % 32)) & 1) == 1) z2[i] = -z[i]; - else z2[i]=z[i]; + if (((s >> (i % 32)) & 1) == 1) + z2[i] = -e_rx[i]; + else + z2[i]=e_rx[i]; } - printf("Encoded Payload (length:%d dwords):\n", length>>5); + printf("Encoded Payload (length:%d dwords):\n", length); - for (int i=0; i>5; i++) - printf("[%d]->0x%08x \t", i, z2[i]); + for (int i=0; i0x%x \t", i, z2[i]); } @@ -855,7 +858,8 @@ static uint16_t nr_dci_false_detection(uint64_t *dci, return x; } -uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, +uint8_t nr_dci_decoding_procedure(int16_t e_rx[4*2*100*12], + PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, fapi_nr_dci_indication_t *dci_ind, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15) { @@ -891,10 +895,10 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, LOG_D(PHY, "Trying DCI candidate %d of %d number of candidates, CCE %d (%d), L %d, length %d, format %s\n", j, rel15->number_of_candidates, CCEind, e_rx_cand_idx, L, dci_length,nr_dci_format_string[rel15->dci_format_options[k]]); - nr_pdcch_unscrambling(&pdcch_vars->e_rx[e_rx_cand_idx], rel15->coreset.scrambling_rnti, L*108, rel15->coreset.pdcch_dmrs_scrambling_id, tmp_e); + nr_pdcch_unscrambling(&e_rx[e_rx_cand_idx], rel15->coreset.scrambling_rnti, L*108, rel15->coreset.pdcch_dmrs_scrambling_id, tmp_e); #ifdef DEBUG_DCI_DECODING - uint32_t *z = (uint32_t *) &pdcch_vars->e_rx[e_rx_cand_idx]; + uint32_t *z = (uint32_t *) &e_rx[e_rx_cand_idx]; for (int index_z = 0; index_z < L*6; index_z++){ for (int i=0; i<9; i++) { LOG_D(PHY,"z[%d]=(%d,%d) \n", (9*index_z + i), *(int16_t *) &z[index_z + i],*(1 + (int16_t *) &z[index_z + i])); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index aac59a7da1..945eb5df0f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -1105,8 +1105,8 @@ uint32_t dlsch_decoding_emul(PHY_VARS_NR_UE *phy_vars_ue, int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15); - + fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, + int16_t e_rx[4*2*100*12]); /*! \brief Extract PSS and SSS resource elements @param phy_vars_ue Pointer to UE variables @@ -1667,7 +1667,8 @@ uint8_t get_prach_prb_offset(NR_DL_FRAME_PARMS *frame_parms, #include -uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, +uint8_t nr_dci_decoding_procedure(int16_t e_rx[4*2*100*12], + PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, fapi_nr_dci_indication_t *dci_ind, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15); diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 04080e7215..3762107d5d 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -611,9 +611,6 @@ typedef struct { /// \brief \f$\overline{w}\f$ from 36-211. /// - first index: ? [0..48*N_RB_DL[ int16_t *wbar; - /// \brief PDCCH/DCI e-sequence (input to rate matching). - /// - first index: ? [0..96*N_RB_DL[ - int16_t *e_rx; /// Total number of PDU errors (diagnostic mode) uint32_t dci_errors; /// Total number of PDU received diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index ddddcd09e2..52fa0d4b2f 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -500,7 +500,8 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, start_meas(&ue->dlsch_rx_pdcch_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_IN); - nr_rx_pdcch(ue, proc, rel15); + int16_t e_rx[4*2*100*12]={0}; + nr_rx_pdcch(ue, proc, rel15, e_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_OUT); @@ -511,7 +512,7 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, n_ss); #endif - dci_cnt = nr_dci_decoding_procedure(ue, proc, dci_ind, rel15); + dci_cnt = nr_dci_decoding_procedure(e_rx, ue, proc, dci_ind, rel15); #ifdef NR_PDCCH_SCHED_DEBUG LOG_I(PHY,"<-NR_PDCCH_PHY_PROCEDURES_LTE_UE (nr_ue_pdcch_procedures)-> Ending function nr_dci_decoding_procedure() -> dci_cnt=%u\n",dci_cnt); From a7e7d05da340aa0aadb134a49773071e3e159c8e Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 16 Mar 2022 21:23:53 +0100 Subject: [PATCH 061/226] fix difficult to read code --- executables/nr-gnb.c | 1 + executables/nr-uesoftmodem.c | 10 +- .../PHY/LTE_ESTIMATION/lte_est_freq_offset.c | 18 +-- openair1/PHY/LTE_ESTIMATION/lte_sync_time.c | 22 +-- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 2 +- .../LTE_TRANSPORT/transport_common_proto.h | 2 +- openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c | 2 +- .../PHY/LTE_UE_TRANSPORT/transport_proto_ue.h | 10 -- openair1/PHY/NR_REFSIG/pss_nr.h | 6 - openair1/PHY/NR_REFSIG/ptrs_nr.c | 6 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 46 +++--- openair1/PHY/NR_TRANSPORT/nr_dlsch.h | 4 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 12 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 3 +- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 6 +- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 12 +- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 10 -- openair1/PHY/NR_UE_TRANSPORT/pss_nr.c | 75 ++++------ openair1/PHY/TOOLS/angle.c | 2 +- openair1/PHY/TOOLS/cadd_sv.c | 2 +- openair1/PHY/TOOLS/cadd_vv.c | 2 +- openair1/PHY/TOOLS/calibration_test.c | 10 +- openair1/PHY/TOOLS/nr_phy_scope.c | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 2 +- openair1/SIMULATION/NR_PHY/pucchsim.c | 2 +- .../unit_tests/src/frame_config_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/harq_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/pbch_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/pss_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/pss_util_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/pss_util_test.h | 2 +- .../unit_tests/src/pucch_uci_generator_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/pucch_uci_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/srs_test.c | 2 +- .../NR_UE_PHY/unit_tests/src/sss_test.c | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 15 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 128 +++++----------- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 3 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 6 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 79 ++++------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 137 ++++++------------ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 2 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 6 +- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 2 +- targets/ARCH/rfsimulator/apply_channelmod.c | 6 +- targets/ARCH/rfsimulator/rfsimulator.h | 4 +- targets/ARCH/rfsimulator/simulator.c | 8 +- targets/RT/USER/lte-ue.c | 2 +- 49 files changed, 258 insertions(+), 431 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 4793ef4e95..b6c95de4ce 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -458,6 +458,7 @@ void init_gNB_Tpool(int inst) { for (int i=0; i < 2; i++) { notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,gNB->L1_tx_out,tx_func); processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + memset(msgDataTx,0, sizeof(processingData_L1tx_t)); init_DLSCH_struct(gNB, msgDataTx); memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t)); pushNotifiedFIFO(gNB->L1_tx_free,msgL1Tx); // to unblock the process in the beginning diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 649b68631b..82ba86ea63 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -241,16 +241,16 @@ nrUE_params_t *get_nrUE_params(void) { } /* initialie thread pools used for NRUE processing paralleliation */ void init_tpools(uint8_t nun_dlsch_threads) { - char params[NR_RX_NB_TH*NR_NB_TH_SLOT*3+1]; + char params[NR_RX_NB_TH*NR_NB_TH_SLOT*3+1]={0}; for (int i=0; iN_RB_DL/2 - 1)*12,dl_ch_shift); //omega = dot_product(dl_ch,dl_ch_prev,frame_parms->ofdm_symbol_size,15); - omega_cpx.r = ((struct complex16*) &omega)->r; - omega_cpx.i = ((struct complex16*) &omega)->i; + omega_cpx.r = ((c16_t*) &omega)->r; + omega_cpx.i = ((c16_t*) &omega)->i; dl_ch = (int16_t *)&dl_ch_estimates[aa][(((frame_parms->N_RB_DL/2) + 1)*12) + ch_offset]; @@ -155,8 +155,8 @@ int lte_est_freq_offset(int **dl_ch_estimates, // calculate omega = angle(conj(dl_ch)*dl_ch_prev)) omega = dot_product(dl_ch,dl_ch_prev,((frame_parms->N_RB_DL/2) - 1)*12,dl_ch_shift); - omega_cpx.r += ((struct complex16*) &omega)->r; - omega_cpx.i += ((struct complex16*) &omega)->i; + omega_cpx.r += ((c16_t*) &omega)->r; + omega_cpx.i += ((c16_t*) &omega)->i; // phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); phase_offset += atan2((double)omega_cpx.i,(double)omega_cpx.r); @@ -195,7 +195,7 @@ int lte_mbsfn_est_freq_offset(int **dl_ch_estimates, { int ch_offset, omega, dl_ch_shift; - struct complex16 *omega_cpx; + c16_t *omega_cpx; double phase_offset; int freq_offset_est; unsigned char aa; @@ -234,7 +234,7 @@ int lte_mbsfn_est_freq_offset(int **dl_ch_estimates, // printf("Computing freq_offset\n"); omega = dot_product(dl_ch,dl_ch_prev,(frame_parms->N_RB_DL/2 - 1)*12,dl_ch_shift); //omega = dot_product(dl_ch,dl_ch_prev,frame_parms->ofdm_symbol_size,15); - omega_cpx = (struct complex16*) ω + omega_cpx = (c16_t*) ω // printf("omega (%d,%d)\n",omega_cpx->r,omega_cpx->i); @@ -247,8 +247,8 @@ int lte_mbsfn_est_freq_offset(int **dl_ch_estimates, // calculate omega = angle(conj(dl_ch)*dl_ch_prev)) omega = dot_product(dl_ch,dl_ch_prev,((frame_parms->N_RB_DL/2) - 1)*12,dl_ch_shift); - omega_cpx->r += ((struct complex16*) &omega)->r; - omega_cpx->i += ((struct complex16*) &omega)->i; + omega_cpx->r += ((c16_t*) &omega)->r; + omega_cpx->i += ((c16_t*) &omega)->i; // phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); // printf("omega (%d,%d) -> %f\n",omega_cpx->r,omega_cpx->i,phase_offset); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c index 1fbc8b7ef2..b21f526fcc 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c @@ -34,9 +34,9 @@ // Note: this is for prototype of generate_drs_pusch (OTA synchronization of RRUs) #include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h" -static struct complex16 *primary_synch0_time __attribute__((aligned(32))); -static struct complex16 *primary_synch1_time __attribute__((aligned(32))); -static struct complex16 *primary_synch2_time __attribute__((aligned(32))); +static c16_t *primary_synch0_time __attribute__((aligned(32))); +static c16_t *primary_synch1_time __attribute__((aligned(32))); +static c16_t *primary_synch2_time __attribute__((aligned(32))); static void doIdft(int size, short *in, short *out) { switch (size) { @@ -67,7 +67,7 @@ static void doIdft(int size, short *in, short *out) { } } -static void copyPrimary( struct complex16 *out, struct complex16 *in, int ofdmSize) { +static void copyPrimary( c16_t *out, struct complex16 *in, int ofdmSize) { int k=ofdmSize-36; for (int i=0; i<72; i++) { @@ -83,20 +83,20 @@ static void copyPrimary( struct complex16 *out, struct complex16 *in, int ofdmSi } int lte_sync_time_init(LTE_DL_FRAME_PARMS *frame_parms ) { // LTE_UE_COMMON *common_vars - struct complex16 syncF_tmp[2048]__attribute__((aligned(32)))= {{0}}; + c16_t syncF_tmp[2048]__attribute__((aligned(32)))= {{0}}; int sz=frame_parms->ofdm_symbol_size*sizeof(*primary_synch0_time); - AssertFatal( NULL != (primary_synch0_time = (struct complex16 *)malloc16(sz)),""); + AssertFatal( NULL != (primary_synch0_time = (c16_t *)malloc16(sz)),""); bzero(primary_synch0_time,sz); - AssertFatal( NULL != (primary_synch1_time = (struct complex16 *)malloc16(sz)),""); + AssertFatal( NULL != (primary_synch1_time = (c16_t *)malloc16(sz)),""); bzero(primary_synch1_time,sz); - AssertFatal( NULL != (primary_synch2_time = (struct complex16 *)malloc16(sz)),""); + AssertFatal( NULL != (primary_synch2_time = (c16_t *)malloc16(sz)),""); bzero(primary_synch2_time,sz); // generate oversampled sync_time sequences - copyPrimary( syncF_tmp, (struct complex16 *) primary_synch0, frame_parms->ofdm_symbol_size); + copyPrimary( syncF_tmp, (c16_t *) primary_synch0, frame_parms->ofdm_symbol_size); doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch0_time); - copyPrimary( syncF_tmp, (struct complex16 *) primary_synch1, frame_parms->ofdm_symbol_size); + copyPrimary( syncF_tmp, (c16_t *) primary_synch1, frame_parms->ofdm_symbol_size); doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch1_time); - copyPrimary( syncF_tmp, (struct complex16 *) primary_synch2, frame_parms->ofdm_symbol_size); + copyPrimary( syncF_tmp, (c16_t *) primary_synch2, frame_parms->ofdm_symbol_size); doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch2_time); if ( LOG_DUMPFLAG(DEBUG_LTEESTIM)){ diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index c6b312cc61..de21b7f4e2 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -2237,7 +2237,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, int P1_SHIFT[13],P2_SHIFT[13]; int offset,nushiftmod3; - uint8_t get_pmi_temp; + int get_pmi_temp; MIMO_mode_t mimo_mode = -1; uint8_t mprime=0,Ns; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h b/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h index af8e63c3ed..e6240a4e78 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h @@ -299,7 +299,7 @@ uint64_t pmi2hex_2Ar1(uint32_t pmi); uint64_t pmi2hex_2Ar2(uint32_t pmi); -uint8_t get_pmi(uint8_t N_RB_DL,MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb); +uint8_t get_pmi(int N_RB_DL,MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb); // DL power control functions double get_pa_dB(uint8_t pa); diff --git a/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c b/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c index 7bbe8e8942..6ab2ad9fdd 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c @@ -21,7 +21,7 @@ #include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h" -uint8_t get_pmi(uint8_t N_RB_DL, MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb) +uint8_t get_pmi(int N_RB_DL, MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb) { /* MIMO_mode_t mode = dlsch_harq->mimo_mode; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h index c5d096ceb7..bdfe0b8d07 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h @@ -1550,16 +1550,6 @@ uint64_t cqi2hex(uint32_t cqi); uint16_t computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); - -/** \brief This routine extracts a single subband PMI from a bitmap coming from UCI or the pmi_extend function - @param N_RB_DL number of resource blocks - @param mimo_mode - @param pmi_alloc subband PMI bitmap - @param rb resource block for which to extract PMI - @returns subband PMI -*/ -uint8_t get_pmi(uint8_t N_RB_DL,MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb); - int get_nCCE_offset_l1(int *CCE_table, const unsigned char L, const int nCCE, diff --git a/openair1/PHY/NR_REFSIG/pss_nr.h b/openair1/PHY/NR_REFSIG/pss_nr.h index b32d48a2e9..c65ca3799d 100644 --- a/openair1/PHY/NR_REFSIG/pss_nr.h +++ b/openair1/PHY/NR_REFSIG/pss_nr.h @@ -113,12 +113,6 @@ EXTERN int16_t *primary_synchro_time_nr[NUMBER_PSS_SEQUENCE] #endif ; -EXTERN int64_t *pss_corr_ue[NUMBER_PSS_SEQUENCE] -#ifdef INIT_VARIABLES_PSS_NR_H -= { NULL, NULL, NULL} -#endif -; - /* profiling structure */ EXTERN time_stats_t generic_time[TIME_LAST]; diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.c b/openair1/PHY/NR_REFSIG/ptrs_nr.c index 40a6a56611..68134eb02d 100644 --- a/openair1/PHY/NR_REFSIG/ptrs_nr.c +++ b/openair1/PHY/NR_REFSIG/ptrs_nr.c @@ -268,8 +268,8 @@ void nr_ptrs_cpe_estimation(uint8_t K_ptrs, return; } uint16_t sc_per_symbol = (nb_rb + K_ptrs - 1)/K_ptrs; - struct complex16 ptrs_p[(1 + sc_per_symbol/4)*4]; - struct complex16 dmrs_comp_p[(1 + sc_per_symbol/4)*4]; + c16_t ptrs_p[(1 + sc_per_symbol/4)*4]; + c16_t dmrs_comp_p[(1 + sc_per_symbol/4)*4]; double abs = 0.0; double real = 0.0; double imag = 0.0; @@ -422,7 +422,7 @@ void get_slope_from_estimates(uint8_t start, uint8_t end, int16_t *est_p, double /* estimate from slope */ void ptrs_estimate_from_slope(int16_t *error_est, double *slope_p, uint8_t start, uint8_t end) { - struct complex16 *error=(struct complex16 *) error_est; + c16_t *error=(struct complex16 *) error_est; for(uint8_t i = 1; i< (end -start);i++) { error[start+i].r = error[start].r + (int16_t)(i * slope_p[0]);// real error[start+i].i = error[start].i + (int16_t)(i * slope_p[1]); //imag diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 876d6cc83a..e4fe9b8371 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -98,7 +98,6 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, uint16_t nb_re = ((12*rel15->NrOfSymbols)-nb_re_dmrs*dmrs_len-xOverhead)*rel15->rbSize*rel15->nrOfLayers; uint8_t Qm = rel15->qamModOrder[0]; uint32_t encoded_length = nb_re*Qm; - uint32_t scrambled_output[rel15->NrOfCodewords][(encoded_length>>5)+1]; int16_t mod_dmrs[n_dmrs<<1] __attribute__ ((aligned(16))); /* PTRS */ @@ -125,7 +124,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, start_meas(dlsch_encoding_stats); if (nr_dlsch_encoding(gNB, - harq->pdu, frame, slot, dlsch, frame_parms,output,tinput,tprep,tparity,toutput, + frame, slot, harq, frame_parms,output,tinput,tprep,tparity,toutput, dlsch_rate_matching_stats, dlsch_interleaving_stats, dlsch_segmentation_stats) == -1) @@ -148,46 +147,41 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, #endif /// scrambling - start_meas(dlsch_scrambling_stats); for (int q=0; qNrOfCodewords; q++) { - memset((void*)scrambled_output[q], 0, ((encoded_length>>5)+1)*sizeof(uint32_t)); + uint32_t scrambled_output[encoded_length]; + start_meas(dlsch_scrambling_stats); nr_pdsch_codeword_scrambling(output, encoded_length, q, rel15->dataScramblingId, rel15->rnti, - scrambled_output[q]); - } - - stop_meas(dlsch_scrambling_stats); + scrambled_output); + stop_meas(dlsch_scrambling_stats); + #ifdef DEBUG_DLSCH - printf("PDSCH scrambling:\n"); - for (int i=0; i>8; i++) { - for (int j=0; j<8; j++) - printf("0x%08x\t", scrambled_output[0][(i<<3)+j]); - printf("\n"); - } + printf("PDSCH scrambling:\n"); + for (int i=0; i>8; i++) { + for (int j=0; j<8; j++) + printf("0x%08x\t", scrambled_output[(i<<3)+j]); + printf("\n"); + } #endif - - /// Modulation start_meas(dlsch_modulation_stats); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 1); - for (int q=0; qNrOfCodewords; q++) - nr_modulation(scrambled_output[q], + nr_modulation(scrambled_output, encoded_length, Qm, mod_symbs[q]); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0); stop_meas(dlsch_modulation_stats); #ifdef DEBUG_DLSCH - printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re); - for (int i=0; i>3; i++) { - for (int j=0; j<8; j++) { - printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]); + printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re); + for (int i=0; i>3; i++) { + for (int j=0; j<8; j++) { + printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]); + } + printf("\n"); } - printf("\n"); - } #endif + } start_meas(&gNB->dlsch_layer_mapping_stats); /// Layer mapping diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h index 28676b49f2..daa4ed1723 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h @@ -78,9 +78,9 @@ int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type); NR_gNB_SCH_STATS_t *find_nr_dlsch_stats(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type); int nr_dlsch_encoding(PHY_VARS_gNB *gNB, - unsigned char *a,int frame, + int frame, uint8_t slot, - NR_gNB_DLSCH_t *dlsch, + NR_DL_gNB_HARQ_t *harq, NR_DL_FRAME_PARMS* frame_parms, unsigned char * output, time_stats_t *tinput, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 229f59032e..bf33457aaa 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -286,10 +286,9 @@ void ldpc8blocks( void *p) { } int nr_dlsch_encoding(PHY_VARS_gNB *gNB, - unsigned char *a, int frame, uint8_t slot, - NR_gNB_DLSCH_t *dlsch, + NR_DL_gNB_HARQ_t *harq, NR_DL_FRAME_PARMS *frame_parms, unsigned char * output, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput, @@ -298,13 +297,12 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, encoder_implemparams_t impp; impp.output=output; unsigned int crc=1; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; - impp.Zc = &dlsch->harq_process.Z; + impp.Zc = &harq->Z; float Coderate = 0.0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN); uint32_t A = rel15->TBSize[0]<<3; - + unsigned char *a=harq->pdu; if ( rel15->rnti != SI_RNTI) trace_NRpdu(DIRECTION_DOWNLINK, a, rel15->TBSize[0], 0, WS_C_RNTI, rel15->rnti, frame, slot,0, 0); @@ -317,14 +315,14 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, stats=&gNB->dlsch_stats[i]; } - if (gNB->dlsch_stats[i].rnti == dlsch->rnti) { + if (gNB->dlsch_stats[i].rnti == rel15->rnti) { stats=&gNB->dlsch_stats[i]; break; } } if (stats) { - stats->rnti = dlsch->rnti; + stats->rnti = rel15->rnti; stats->total_bytes_tx += rel15->TBSize[0]; stats->current_RI = rel15->nrOfLayers; stats->current_Qm = rel15->qamModOrder[0]; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 17f145b98a..eda53e1c84 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -405,13 +405,12 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, if (nr_sequences>1) { if (xrtmag_dBtimes10 < (50+xrtmag_next_dBtimes10) || SNRtimes10 < gNB->pucch0_thres) { no_conf=true; - LOG_W(PHY,"%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n", + LOG_D(PHY,"%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n", frame, slot, uci_stats->pucch0_thres, SNRtimes10, xrtmag_dBtimes10, xrtmag_next_dBtimes10); - abort(); } } gNB->bad_pucch += no_conf; diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 66422a9dfa..5b0544bf21 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -820,10 +820,6 @@ void nr_pdcch_unscrambling(int16_t e_rx[4*2*100*12], else z2[i]=e_rx[i]; } - printf("Encoded Payload (length:%d dwords):\n", length); - - for (int i=0; i0x%x \t", i, z2[i]); } @@ -898,7 +894,7 @@ uint8_t nr_dci_decoding_procedure(int16_t e_rx[4*2*100*12], nr_pdcch_unscrambling(&e_rx[e_rx_cand_idx], rel15->coreset.scrambling_rnti, L*108, rel15->coreset.pdcch_dmrs_scrambling_id, tmp_e); #ifdef DEBUG_DCI_DECODING - uint32_t *z = (uint32_t *) &e_rx[e_rx_cand_idx]; + uint32_t *z = (uint32_t *) &pdcch_vars->e_rx[e_rx_cand_idx]; for (int index_z = 0; index_z < L*6; index_z++){ for (int i=0; i<9; i++) { LOG_D(PHY,"z[%d]=(%d,%d) \n", (9*index_z + i), *(int16_t *) &z[index_z + i],*(1 + (int16_t *) &z[index_z + i])); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index bf9cfaaa70..6163a95e5c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -168,8 +168,6 @@ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint dlsch->harq_processes[i]->d[r] = (int16_t *)malloc16(5*8448*sizeof(int16_t)); if (dlsch->harq_processes[i]->c[r]) memset(dlsch->harq_processes[i]->c[r],0,1056); - if (dlsch->harq_processes[i]->d[r]) - memset(dlsch->harq_processes[i]->d[r],0,5*8448); else exit_flag=2; @@ -326,12 +324,12 @@ void nr_processDLSegment(void* arg) { harq_process->rvidx, harq_process->round); */ //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); - + int16_t d[5*8448]; if (nr_rate_matching_ldpc_rx(Ilbrm, Tbslbrm, p_decoderParms->BG, p_decoderParms->Z, - harq_process->d[r], + d, w, harq_process->C, harq_process->rvidx, @@ -353,7 +351,7 @@ void nr_processDLSegment(void* arg) { LOG_D(PHY,"decoder input(segment %u) :",r); for (int i=0; id[r][i]); + LOG_D(PHY,"%d : %d\n",i,d[i]); LOG_D(PHY,"\n"); } @@ -379,9 +377,9 @@ void nr_processDLSegment(void* arg) { //set Filler bits memset((&z[0]+K_bits_F),127,harq_process->F*sizeof(int16_t)); //Move coded bits before filler bits - memcpy((&z[0]+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t)); + memcpy((&z[0]+2*harq_process->Z),d,(K_bits_F-2*harq_process->Z)*sizeof(int16_t)); //skip filler bits - memcpy((&z[0]+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t)); + memcpy((&z[0]+Kr),d+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t)); //Saturate coded bits before decoding into 8 bits values for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 945eb5df0f..ead5ec2da5 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -1480,16 +1480,6 @@ uint64_t cqi2hex(uint32_t cqi); uint16_t computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); - -/** \brief This routine extracts a single subband PMI from a bitmap coming from UCI or the pmi_extend function - @param N_RB_DL number of resource blocks - @param mimo_mode - @param pmi_alloc subband PMI bitmap - @param rb resource block for which to extract PMI - @returns subband PMI -*/ -uint8_t get_pmi(uint8_t N_RB_DL,MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb); - int get_nCCE_offset_l1(int *CCE_table, const unsigned char L, const int nCCE, diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c index 54712cb64e..13ed436273 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c @@ -381,7 +381,6 @@ void init_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue) int sizePss = LENGTH_PSS_NR * IQ_SIZE; /* complex value i & q signed 16 bits */ int size = ofdm_symbol_size * IQ_SIZE; /* i and q samples signed 16 bits */ int16_t *p = NULL; - int64_t *q = NULL; AssertFatal(ofdm_symbol_size > 127, "illegal ofdm_symbol_size %d\n",ofdm_symbol_size); for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) { @@ -410,17 +409,6 @@ void init_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue) assert(0); } - size = sizeof(int64_t)*(frame_parms_ue->samples_per_frame + (2*ofdm_symbol_size)); - q = (int64_t*)malloc16(size); - if (q != NULL) { - pss_corr_ue[i] = q; - bzero( pss_corr_ue[i], size); - } - else { - LOG_E(PHY,"Fatal memory allocation problem \n"); - assert(0); - } - generate_pss_nr(frame_parms_ue,i); } } @@ -443,7 +431,6 @@ void free_context_pss_nr(void) free_and_zero(primary_synchro_nr[i]); free_and_zero(primary_synchro_nr2[i]); free_and_zero(primary_synchro_time_nr[i]); - free_and_zero(pss_corr_ue[i]); } } @@ -801,7 +788,6 @@ static inline double angle64(int64_t x) *********************************************************************/ #define DOT_PRODUCT_SCALING_SHIFT (17) - int pss_search_time_nr(int **rxdata, ///rx data in time domain NR_DL_FRAME_PARMS *frame_parms, int fo_flag, @@ -812,7 +798,7 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain unsigned int n, ar, peak_position, pss_source; int64_t peak_value; int64_t result; - int64_t avg[NUMBER_PSS_SEQUENCE]; + int64_t avg[NUMBER_PSS_SEQUENCE]={0}; double ffo_est=0; // performing the correlation on a frame length plus one symbol for the first of the two frame @@ -823,9 +809,8 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain else length = frame_parms->samples_per_frame; - AssertFatal(length>0,"illegal length %d\n",length); - for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) AssertFatal(pss_corr_ue[i] != NULL,"pss_corr_ue[%d] not yet allocated! Exiting.\n", i); + AssertFatal(length>0,"illegal length %d\n",length); peak_value = 0; peak_position = 0; pss_source = 0; @@ -846,47 +831,41 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain /* Correlation computation is based on a a dot product which is realized thank to SIMS extensions */ for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) { - avg[pss_index]=0; - memset(pss_corr_ue[pss_index],0,length*sizeof(int64_t)); - } - for (n=0; n < length; n+=4) { // + for (n=0; n < length; n+=4) { // - for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) { + int64_t pss_corr_ue=0; + /* calculate dot product of primary_synchro_time_nr and rxdata[ar][n] + * (ar=0..nb_ant_rx) and store the sum in temp[n]; */ + for (ar=0; arnb_antennas_rx; ar++) { - if ( n < (length - frame_parms->ofdm_symbol_size)) { + /* perform correlation of rx data and pss sequence ie it is a dot product */ + result = dot_product64((short*)primary_synchro_time_nr[pss_index], + (short*)&(rxdata[ar][n+is*frame_parms->samples_per_frame]), + frame_parms->ofdm_symbol_size, + shift); + pss_corr_ue += abs64(result); + //((short*)pss_corr_ue[pss_index])[2*n] += ((short*) &result)[0]; /* real part */ + //((short*)pss_corr_ue[pss_index])[2*n+1] += ((short*) &result)[1]; /* imaginary part */ + //((short*)&synchro_out)[0] += ((int*) &result)[0]; /* real part */ + //((short*)&synchro_out)[1] += ((int*) &result)[1]; /* imaginary part */ - /* calculate dot product of primary_synchro_time_nr and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n]; */ - for (ar=0; arnb_antennas_rx; ar++) { - - /* perform correlation of rx data and pss sequence ie it is a dot product */ - result = dot_product64((short*)primary_synchro_time_nr[pss_index], - (short*)&(rxdata[ar][n+is*frame_parms->samples_per_frame]), - frame_parms->ofdm_symbol_size, - shift); - pss_corr_ue[pss_index][n] += abs64(result); - //((short*)pss_corr_ue[pss_index])[2*n] += ((short*) &result)[0]; /* real part */ - //((short*)pss_corr_ue[pss_index])[2*n+1] += ((short*) &result)[1]; /* imaginary part */ - //((short*)&synchro_out)[0] += ((int*) &result)[0]; /* real part */ - //((short*)&synchro_out)[1] += ((int*) &result)[1]; /* imaginary part */ - - } } - + /* calculate the absolute value of sync_corr[n] */ - avg[pss_index]+=pss_corr_ue[pss_index][n]; - if (pss_corr_ue[pss_index][n] > peak_value) { - peak_value = pss_corr_ue[pss_index][n]; + avg[pss_index]+=pss_corr_ue; + if (pss_corr_ue > peak_value) { + peak_value = pss_corr_ue; peak_position = n; pss_source = pss_index; - + #ifdef DEBUG_PSS_NR - printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_ue[pss_index][n]); + printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_ue[n]); #endif } } } - + if (fo_flag){ // fractional frequency offset computation according to Cross-correlation Synchronization Algorithm Using PSS @@ -922,7 +901,8 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain // computing absolute value of frequency offset *f_off = ffo_est*frame_parms->subcarrier_spacing; - for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) avg[pss_index]/=(length/4); + for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) + avg[pss_index]/=(length/4); *eNB_id = pss_source; @@ -937,9 +917,6 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain static int debug_cnt = 0; if (debug_cnt == 0) { - LOG_M("pss_corr_ue0.m","pss_corr_ue0",pss_corr_ue[0],length,1,6); - LOG_M("pss_corr_ue1.m","pss_corr_ue1",pss_corr_ue[1],length,1,6); - LOG_M("pss_corr_ue2.m","pss_corr_ue2",pss_corr_ue[2],length,1,6); if (is) LOG_M("rxdata1.m","rxd0",rxdata[frame_parms->samples_per_frame],length,1,1); else diff --git a/openair1/PHY/TOOLS/angle.c b/openair1/PHY/TOOLS/angle.c index a06640d1cf..89ffc3cb60 100644 --- a/openair1/PHY/TOOLS/angle.c +++ b/openair1/PHY/TOOLS/angle.c @@ -29,7 +29,7 @@ #include "costable.h" #include "defs.h" -unsigned int angle(struct complex16 perror) +unsigned int angle(c16_t perror) { int a; diff --git a/openair1/PHY/TOOLS/cadd_sv.c b/openair1/PHY/TOOLS/cadd_sv.c index caa8d1cc04..56dcb71847 100644 --- a/openair1/PHY/TOOLS/cadd_sv.c +++ b/openair1/PHY/TOOLS/cadd_sv.c @@ -129,7 +129,7 @@ main () short output[256] __attribute__((aligned(16))); int i; - struct complex16 alpha; + c16_t alpha; Zero_Buffer(output,256*2); diff --git a/openair1/PHY/TOOLS/cadd_vv.c b/openair1/PHY/TOOLS/cadd_vv.c index 77346a97f7..08bf514cb3 100644 --- a/openair1/PHY/TOOLS/cadd_vv.c +++ b/openair1/PHY/TOOLS/cadd_vv.c @@ -278,7 +278,7 @@ main () short output[256] __attribute__((aligned(16))); int i; - struct complex16 alpha; + c16_t alpha; Zero_Buffer(output,256*2); diff --git a/openair1/PHY/TOOLS/calibration_test.c b/openair1/PHY/TOOLS/calibration_test.c index 5dced27060..650d5e420c 100644 --- a/openair1/PHY/TOOLS/calibration_test.c +++ b/openair1/PHY/TOOLS/calibration_test.c @@ -305,15 +305,15 @@ int main(int argc, char **argv) { openair0_device_load(&rfdevice,&openair0_cfg); - void ** samplesRx = (void **)malloc16(antennas* sizeof(struct complex16 *) ); - void ** samplesTx = (void **)malloc16(antennas* sizeof(struct complex16 *) ); + void ** samplesRx = (void **)malloc16(antennas* sizeof(c16_t *) ); + void ** samplesTx = (void **)malloc16(antennas* sizeof(c16_t *) ); int fd=open(getenv("rftestInputFile"),O_RDONLY); AssertFatal(fd>=0,"%s",strerror(errno)); for (int i=0; irbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS] __attribute__((aligned(32))); bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); if (input_fd == NULL) { - nr_dlsch_encoding(gNB, test_input, frame, slot, dlsch, frame_parms,output,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + nr_dlsch_encoding(gNB, frame, slot, &dlsch->harq_process, frame_parms,output,NULL,NULL,NULL,NULL,NULL,NULL,NULL); } for (SNR = snr0; SNR < snr1; SNR += snr_step) { diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 151d51d726..b6dc3d8f11 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -551,7 +551,7 @@ int main(int argc, char **argv) if (n_trials==1) printf("txlev %d (%f dB), offset %d, sigma2 %f ( %f dB)\n",txlev,10*log10(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size,sigma2,sigma2_dB); - struct complex16 **rxdataF = (struct complex16 **)gNB->common_vars.rxdataF; + c16_t **rxdataF = (struct complex16 **)gNB->common_vars.rxdataF; for (int symb=0; symbframe_parms.symbols_per_slot;symb++) { if (symb= startingSymbolIndex+nrofSymbols) { int i0 = symb*gNB->frame_parms.ofdm_symbol_size; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/frame_config_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/frame_config_test.c index c88c261667..093bb2d000 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/frame_config_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/frame_config_test.c @@ -285,7 +285,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int Nid_cell[] = {(3*0+0)}; VOID_PARAMETER argc; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/harq_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/harq_test.c index 05170e0bc9..96d7382f2b 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/harq_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/harq_test.c @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int Nid_cell[] = {(3*0+0)}; VOID_PARAMETER argc; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pbch_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pbch_test.c index 7600dfb08f..5c7f3157e7 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pbch_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pbch_test.c @@ -379,7 +379,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int decoded_pbch = -1; int Nid1, Nid2; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_test.c index 2088d558cb..de1249457f 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_test.c @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_rx = 1; uint16_t Nid_cell=123; uint8_t frame_type=FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag=NORMAL; const char *name_test = "PSS NR"; test_t test = { name_test, 0, 0, 0, 0}; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.c index 4334bd12f9..2302c50ab1 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.c @@ -206,7 +206,7 @@ void undefined_function(const char *function) { *********************************************************************/ int init_test(unsigned char N_tx, unsigned char N_rx, unsigned char transmission_mode, - unsigned char extended_prefix_flag, uint8_t frame_type, uint16_t Nid_cell, uint8_t N_RB_DL) { + unsigned char extended_prefix_flag, uint8_t frame_type, uint16_t Nid_cell, int N_RB_DL) { (void) transmission_mode; NR_DL_FRAME_PARMS *frame_parms; int log_level = OAILOG_TRACE; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.h b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.h index f0929e88c0..78efc2234b 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.h +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pss_util_test.h @@ -90,7 +90,7 @@ int set_pss_in_rx_buffer(PHY_VARS_NR_UE *PHY_vars_UE, int position_symbol, int p int init_test(unsigned char N_tx, unsigned char N_rx, unsigned char transmission_mode, unsigned char extended_prefix_flag, uint8_t frame_type, uint16_t Nid_cell, - uint8_t N_RB_DL); + int N_RB_DL); void display_test_configuration_pss(int position, int pss_sequence_number); diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_generator_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_generator_test.c index 68acea6d98..4948d0a876 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_generator_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_generator_test.c @@ -142,7 +142,7 @@ int main(int argc, char *argv[]) { uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=106; + int N_RB_DL=106; lte_prefix_type_t extended_prefix_flag = NORMAL; int Nid_cell[] = {(3*1+3)}; VOID_PARAMETER argc; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c index f731edc20a..31fe15a6de 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c @@ -1239,7 +1239,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int Nid_cell[] = {(3*1+3)}; VOID_PARAMETER argc; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/srs_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/srs_test.c index 34ea68bc61..235387acf7 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/srs_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/srs_test.c @@ -442,7 +442,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int Nid_cell[] = {(3*0+0)}; VOID_PARAMETER argc; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/sss_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/sss_test.c index 34127b604f..6f6594861a 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/sss_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/sss_test.c @@ -181,7 +181,7 @@ int main(int argc, char *argv[]) uint8_t nb_antennas_tx = 1; uint8_t nb_antennas_rx = 1; uint8_t frame_type = FDD; - uint8_t N_RB_DL=100; + int N_RB_DL=100; lte_prefix_type_t extended_prefix_flag = NORMAL; int phase; int Nid1, Nid2; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index ba3128923f..f084cb2d63 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -109,8 +109,7 @@ typedef struct { uint8_t LCID: 6; // octet 1 [5:0] uint8_t F: 1; // octet 1 [6] uint8_t R: 1; // octet 1 [7] - uint8_t L1: 8; // octet 2 [7:0] - uint8_t L2: 8; // octet 3 [7:0] + uint16_t L: 16; // octet 2 [7:0] } __attribute__ ((__packed__)) NR_MAC_SUBHEADER_LONG; typedef struct { @@ -118,6 +117,18 @@ typedef struct { uint8_t R: 2; // octet 1 [7:6] } __attribute__ ((__packed__)) NR_MAC_SUBHEADER_FIXED; +static inline void getMacLen(uint8_t* pdu, uint16_t *mac_ce_len, uint16_t *mac_subheader_len) { + NR_MAC_SUBHEADER_SHORT *s=(NR_MAC_SUBHEADER_SHORT*) pdu; + NR_MAC_SUBHEADER_LONG *l=(NR_MAC_SUBHEADER_LONG*) pdu; + if (s->F) { + *mac_subheader_len=sizeof(*l); + *mac_ce_len=ntohs(l->L); + } else { + *mac_subheader_len=sizeof(*s); + *mac_ce_len=s->L; + } +} + // BSR MAC CEs // TS 38.321 ch. 6.1.3.1 // Short BSR for a specific logical channel group ID diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 0c339ee70a..05313f388a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3326,10 +3326,6 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment, int pdu_id){ - uint8_t rx_lcid; - uint16_t mac_ce_len; - uint16_t mac_subheader_len; - uint16_t mac_sdu_len; module_id_t module_idP = dl_info->module_id; frame_t frameP = dl_info->frame; int slot = dl_info->slot; @@ -3348,10 +3344,9 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, LOG_D(MAC, "In %s [%d.%d]: processing PDU %d (with length %d) of %d total number of PDUs...\n", __FUNCTION__, frameP, slot, pdu_id, pdu_len, dl_info->rx_ind->number_pdus); while (!done && pdu_len > 0){ - mac_ce_len = 0x0000; - mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct - mac_sdu_len = 0x0000; - rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID; + uint16_t mac_len = 0x0000; + uint16_t mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct + uint8_t rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID; LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", rx_lcid, pdu_len); switch(rx_lcid){ @@ -3359,128 +3354,89 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, case DL_SCH_LCID_CCCH: // MSG4 RRC Setup 38.331 // variable length - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *) pduP)->L1 & 0x7f) << 8) - | ((uint16_t)((NR_MAC_SUBHEADER_LONG *) pduP)->L2 & 0xff); - mac_subheader_len = 3; - } else { - mac_sdu_len = ((NR_MAC_SUBHEADER_SHORT *) pduP)->L; - mac_subheader_len = 2; - } - - AssertFatal(pdu_len > mac_sdu_len, "The mac_sdu_len (%d) has an invalid size. PDU len = %d! \n", - mac_sdu_len, pdu_len); + getMacLen(pduP, &mac_len, &mac_subheader_len); + AssertFatal(pdu_len > mac_len, "The mac_len (%d) has an invalid size. PDU len = %d! \n", + mac_len, pdu_len); // Check if it is a valid CCCH message, we get all 00's messages very often int i = 0; - for(i=0; i<(mac_subheader_len+mac_sdu_len); i++) { + for(i=0; i<(mac_subheader_len+mac_len); i++) { if(pduP[i] != 0) { break; } } - if (i == (mac_subheader_len+mac_sdu_len)) { + if (i == (mac_subheader_len+mac_len)) { LOG_D(NR_MAC, "%s() Invalid CCCH message!, pdu_len: %d\n", __func__, pdu_len); done = 1; break; } - if ( mac_sdu_len > 0 ) { - LOG_D(NR_MAC,"DL_SCH_LCID_CCCH (e.g. RRCSetup) with payload len %d\n", mac_sdu_len); + if ( mac_len > 0 ) { + LOG_D(NR_MAC,"DL_SCH_LCID_CCCH (e.g. RRCSetup) with payload len %d\n", mac_len); for (int i = 0; i < mac_subheader_len; i++) { LOG_D(NR_MAC, "MAC header %d: 0x%x\n", i, pduP[i]); } - for (int i = 0; i < mac_sdu_len; i++) { + for (int i = 0; i < mac_len; i++) { LOG_D(NR_MAC, "%d: 0x%x\n", i, pduP[mac_subheader_len + i]); } - nr_mac_rrc_data_ind_ue(module_idP, CC_id, gNB_index, frameP, 0, mac->crnti, CCCH, pduP+mac_subheader_len, mac_sdu_len); + nr_mac_rrc_data_ind_ue(module_idP, CC_id, gNB_index, frameP, 0, mac->crnti, CCCH, pduP+mac_subheader_len, mac_len); } break; case DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH: + case DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL: + case DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT: + case DL_SCH_LCID_SP_SRS_ACTIVATION: // 38.321 Ch6.1.3.14 // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL: - // 38.321 Ch6.1.3.13 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT: - // 38.321 Ch6.1.3.12 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_SP_SRS_ACTIVATION: - // 38.321 Ch6.1.3.17 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } + getMacLen(pduP, &mac_len, &mac_subheader_len); break; + case DL_SCH_LCID_RECOMMENDED_BITRATE: // 38.321 Ch6.1.3.20 - mac_ce_len = 2; + mac_len = 2; break; case DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT: // 38.321 Ch6.1.3.19 - mac_ce_len = 2; + mac_len = 2; break; case DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT: // 38.321 Ch6.1.3.18 - mac_ce_len = 3; + mac_len = 3; break; case DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT: // 38.321 Ch6.1.3.16 - mac_ce_len = 2; + mac_len = 2; break; case DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH: // 38.321 Ch6.1.3.15 - mac_ce_len = 2; + mac_len = 2; break; case DL_SCH_LCID_DUPLICATION_ACT: // 38.321 Ch6.1.3.11 - mac_ce_len = 1; + mac_len = 1; break; case DL_SCH_LCID_SCell_ACT_4_OCT: // 38.321 Ch6.1.3.10 - mac_ce_len = 4; + mac_len = 4; break; case DL_SCH_LCID_SCell_ACT_1_OCT: // 38.321 Ch6.1.3.10 - mac_ce_len = 1; + mac_len = 1; break; case DL_SCH_LCID_L_DRX: // 38.321 Ch6.1.3.6 // fixed length but not yet specify. - mac_ce_len = 0; + mac_len = 0; break; case DL_SCH_LCID_DRX: // 38.321 Ch6.1.3.5 // fixed length but not yet specify. - mac_ce_len = 0; + mac_len = 0; break; case DL_SCH_LCID_TA_COMMAND: // 38.321 Ch6.1.3.4 - mac_ce_len = 1; + mac_len = 1; /*uint8_t ta_command = ((NR_MAC_CE_TA *)pduP)[1].TA_COMMAND; uint8_t tag_id = ((NR_MAC_CE_TA *)pduP)[1].TAGID;*/ @@ -3502,14 +3458,14 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, // Clause 5.1.5 and 6.1.3.3 of 3GPP TS 38.321 version 16.2.1 Release 16 // MAC Header: 1 byte (R/R/LCID) // MAC SDU: 6 bytes (UE Contention Resolution Identity) - mac_ce_len = 6; + mac_len = 6; if(ra->ra_state == WAIT_CONTENTION_RESOLUTION) { LOG_I(MAC, "[UE %d][RAPROC] Frame %d : received contention resolution identity: 0x%02x%02x%02x%02x%02x%02x Terminating RA procedure\n", module_idP, frameP, pduP[1], pduP[2], pduP[3], pduP[4], pduP[5], pduP[6]); bool ra_success = true; - for(int i = 0; icont_res_id[i] != pduP[i+1]) { ra_success = false; break; @@ -3540,22 +3496,8 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, // check if LCID is valid at current time. if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) return; - NR_MAC_SUBHEADER_SHORT *shs = (NR_MAC_SUBHEADER_SHORT *)pduP; - if (shs->F) { - //mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return; - NR_MAC_SUBHEADER_LONG *shl = (NR_MAC_SUBHEADER_LONG *)pduP; - mac_sdu_len = ((uint16_t)(shl->L1 & 0x7f) << 8) | (uint16_t)(shl->L2 & 0xff); - } else { - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return; - mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - } - - LOG_D(NR_MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, gNB_index, mac_sdu_len); + getMacLen(pduP, &mac_len, &mac_subheader_len); + LOG_D(NR_MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, gNB_index, mac_len); #if defined(ENABLE_MAC_PAYLOAD_DEBUG) LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); @@ -3576,7 +3518,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, MBMS_FLAG_NO, rx_lcid, (char *) (pduP + mac_subheader_len), - mac_sdu_len, + mac_len, 1, NULL); } else { @@ -3587,8 +3529,8 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, break; } } - pduP += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); - pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + pduP += ( mac_subheader_len + mac_len ); + pdu_len -= ( mac_subheader_len + mac_len ); if (pdu_len < 0) LOG_E(MAC, "[UE %d][%d.%d] nr_ue_process_mac_pdu, residual mac pdu length %d < 0!\n", module_idP, frameP, slot, pdu_len); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index bc9895ac2e..05c57d19ea 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -3118,8 +3118,7 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, header->R = 0; header->F = 1; header->LCID = lcid; - header->L1 = ((unsigned short) sdu_length >> 8) & 0x7f; - header->L2 = (unsigned short) sdu_length & 0xff; + header->L = htons(sdu_length); #ifdef ENABLE_MAC_PAYLOAD_DEBUG LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index f36dbc4a16..2263f4656b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1619,7 +1619,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra harq->feedback_slot = pucch->ul_slot; harq->feedback_frame = pucch->frame; - uint8_t *buf = (uint8_t *) harq->tb; + uint8_t *buf = (uint8_t *) harq->transportBlock; // Bytes to be transmitted if (harq->round == 0) { if (ra->msg3_dcch_dtch) { @@ -1866,11 +1866,11 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra } T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(ra->rnti), - T_INT(frameP), T_INT(slotP), T_INT(current_harq_pid), T_BUFFER(harq->tb, harq->tb_size)); + T_INT(frameP), T_INT(slotP), T_INT(current_harq_pid), T_BUFFER(harq->transportBlock, harq->tb_size)); // DL TX request nfapi_nr_pdu_t *tx_req = &nr_mac->TX_req[CC_id].pdu_list[nr_mac->TX_req[CC_id].Number_of_PDUs]; - memcpy(tx_req->TLVs[0].value.direct, harq->tb, sizeof(uint8_t) * harq->tb_size); + memcpy(tx_req->TLVs[0].value.direct, harq->transportBlock, sizeof(uint8_t) * harq->tb_size); tx_req->PDU_length = harq->tb_size; tx_req->PDU_index = pduindex; tx_req->num_TLV = 1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5032ee601f..ccbd6d43f8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1320,12 +1320,12 @@ void nr_schedule_ue_spec(module_id_t module_id, current_harq_pid); T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), - T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->tb, TBS)); + T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock, TBS)); } else { /* initial transmission */ LOG_D(NR_MAC, "[%s] Initial HARQ transmission in %d.%d\n", __FUNCTION__, frame, slot); - uint8_t *buf = (uint8_t *) harq->tb; + uint8_t *buf = (uint8_t *) harq->transportBlock; /* first, write all CEs that might be there */ int written = nr_write_ce_dlsch_pdu(module_id, @@ -1334,8 +1334,8 @@ void nr_schedule_ue_spec(module_id_t module_id, 255, // no drx NULL); // contention res id buf += written; - int size = TBS - written; - DevAssert(size >= 0); + uint8_t* bufEnd = buf + TBS - written; + DevAssert(TBS > written); /* next, get RLC data */ @@ -1345,18 +1345,15 @@ void nr_schedule_ue_spec(module_id_t module_id, start_meas(&gNB_mac->rlc_data_req); if (sched_ctrl->num_total_bytes > 0) { tbs_size_t len = 0; - while (size > 3) { + while (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) + 1 ) { // we do not know how much data we will get from RLC, i.e., whether it // will be longer than 256B or not. Therefore, reserve space for long header, then // fetch data, then fill real length NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; - buf += 3; - size -= 3; - /* limit requested number of bytes to what preprocessor specified, or * such that TBS is full */ - const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, size); - + const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, + bufEnd-buf-+sizeof(NR_MAC_SUBHEADER_LONG)); len = mac_rlc_data_req(module_id, rnti, module_id, @@ -1365,12 +1362,12 @@ void nr_schedule_ue_spec(module_id_t module_id, MBMS_FLAG_NO, lcid, ndata, - (char *)buf, + (char *)buf+sizeof(NR_MAC_SUBHEADER_LONG), 0, 0); - + LOG_D(NR_MAC, - "%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %d)\n", + "%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n", frame, slot, rnti, @@ -1378,59 +1375,45 @@ void nr_schedule_ue_spec(module_id_t module_id, lcid < 4 ? "DCCH" : "DTCH", lcid, ndata, - size); + bufEnd-buf-+sizeof(NR_MAC_SUBHEADER_LONG)); if (len == 0) break; header->R = 0; header->F = 1; header->LCID = lcid; - header->L1 = (len >> 8) & 0xff; - header->L2 = len & 0xff; - size -= len; - buf += len; + header->L = htons(len); + buf += len+sizeof(NR_MAC_SUBHEADER_LONG); dlsch_total_bytes += len; } - if (len == 0) { - /* RLC did not have data anymore, mark buffer as unused */ - buf -= 3; - size += 3; - } } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra || get_softmodem_params()->sa) { /* we will need the large header, phy-test typically allocates all * resources and fills to the last byte below */ - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; - buf += 3; - size -= 3; - DevAssert(size > 0); - LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d with %d B of random data\n", frame, slot, TBS, size); - // fill dlsch_buffer with random data - for (int i = 0; i < size; i++) - buf[i] = lrand48() & 0xff; - header->R = 0; - header->F = 1; - header->LCID = DL_SCH_LCID_PADDING; - header->L1 = (size >> 8) & 0xff; - header->L2 = size & 0xff; - size -= size; - buf += size; - dlsch_total_bytes += size; + LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d of random data\n", frame, slot, TBS); + if (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) ) { + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; + // fill dlsch_buffer with random data + header->R = 0; + header->F = 1; + header->LCID = DL_SCH_LCID_PADDING; + buf += sizeof(NR_MAC_SUBHEADER_LONG); + header->L = htons(bufEnd-buf); + dlsch_total_bytes += bufEnd-buf; + for (; buf < bufEnd; buf++) + *buf = lrand48() & 0xff; + } } stop_meas(&gNB_mac->rlc_data_req); // Add padding header and zero rest out if there is space left - if (size > 0) { + if (bufEnd-buf > 0) { NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf; padding->R = 0; padding->LCID = DL_SCH_LCID_PADDING; - size -= 1; buf += 1; - while (size > 0) { - *buf = 0; - buf += 1; - size -= 1; - } + memset(buf,0,bufEnd-buf); + buf=bufEnd; } UE_info->mac_stats[UE_id].dlsch_total_bytes += TBS; @@ -1455,7 +1438,7 @@ void nr_schedule_ue_spec(module_id_t module_id, } T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), - T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(harq->tb, TBS)); + T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(harq->transportBlock, TBS)); } const int ntx_req = gNB_mac->TX_req[CC_id].Number_of_PDUs; @@ -1464,7 +1447,7 @@ void nr_schedule_ue_spec(module_id_t module_id, tx_req->PDU_index = pduindex; tx_req->num_TLV = 1; tx_req->TLVs[0].length = TBS + 2; - memcpy(tx_req->TLVs[0].value.direct, harq->tb, TBS); + memcpy(tx_req->TLVs[0].value.direct, harq->transportBlock, TBS); gNB_mac->TX_req[CC_id].Number_of_PDUs++; gNB_mac->TX_req[CC_id].SFN = frame; gNB_mac->TX_req[CC_id].Slot = slot; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index aa49b14fe5..6c89d30800 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -205,11 +205,7 @@ int nr_process_mac_pdu(module_id_t module_idP, int pdu_len) { - uint8_t rx_lcid; uint8_t done = 0; - uint16_t mac_ce_len; - uint16_t mac_subheader_len; - uint16_t mac_sdu_len; NR_UE_info_t *UE_info = &RC.nrmac[module_idP]->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; @@ -223,10 +219,9 @@ int nr_process_mac_pdu(module_id_t module_idP, #endif while (!done && pdu_len > 0){ - mac_ce_len = 0; - mac_subheader_len = sizeof(NR_MAC_SUBHEADER_FIXED); - mac_sdu_len = 0; - rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID; + uint16_t mac_len=0; + uint16_t mac_subheader_len=sizeof(NR_MAC_SUBHEADER_FIXED); + uint8_t rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID; LOG_D(NR_MAC, "In %s: received UL-SCH sub-PDU with LCID 0x%x in %d.%d (remaining PDU length %d)\n", __func__, rx_lcid, frameP, slot, pdu_len); @@ -241,7 +236,7 @@ int nr_process_mac_pdu(module_id_t module_idP, #endif*/ case UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY: // 38.321 Ch6.1.3.20 - mac_ce_len = 2; + mac_len = 2; break; case UL_SCH_LCID_CONFIGURED_GRANT_CONFIRMATION: // 38.321 Ch6.1.3.7 @@ -251,7 +246,7 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_S_TRUNCATED_BSR: //38.321 section 6.1.3.1 //fixed length - mac_ce_len =1; + mac_len =1; /* Extract short BSR value */ ce_ptr = &pduP[mac_subheader_len]; NR_BSR_SHORT *bsr_s = (NR_BSR_SHORT *) ce_ptr; @@ -269,25 +264,20 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_L_BSR: case UL_SCH_LCID_L_TRUNCATED_BSR: - //38.321 section 6.1.3.1 - //variable length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } - /* Extract long BSR value */ - ce_ptr = &pduP[mac_subheader_len]; - NR_BSR_LONG *bsr_l = (NR_BSR_LONG *) ce_ptr; - sched_ctrl->estimated_ul_buffer = 0; + //38.321 section 6.1.3.1 + //variable length + getMacLen(pduP, &mac_len, &mac_subheader_len); + /* Extract long BSR value */ + ce_ptr = &pduP[mac_subheader_len]; + NR_BSR_LONG *bsr_l = (NR_BSR_LONG *) ce_ptr; + sched_ctrl->estimated_ul_buffer = 0; + + n_Lcg = bsr_l->LcgID7 + bsr_l->LcgID6 + bsr_l->LcgID5 + bsr_l->LcgID4 + + bsr_l->LcgID3 + bsr_l->LcgID2 + bsr_l->LcgID1 + bsr_l->LcgID0; - n_Lcg = bsr_l->LcgID7 + bsr_l->LcgID6 + bsr_l->LcgID5 + bsr_l->LcgID4 + - bsr_l->LcgID3 + bsr_l->LcgID2 + bsr_l->LcgID1 + bsr_l->LcgID0; - - LOG_D(NR_MAC, "LONG BSR, LCG ID(7-0) %d/%d/%d/%d/%d/%d/%d/%d\n", - bsr_l->LcgID7, bsr_l->LcgID6, bsr_l->LcgID5, bsr_l->LcgID4, - bsr_l->LcgID3, bsr_l->LcgID2, bsr_l->LcgID1, bsr_l->LcgID0); + LOG_D(NR_MAC, "LONG BSR, LCG ID(7-0) %d/%d/%d/%d/%d/%d/%d/%d\n", + bsr_l->LcgID7, bsr_l->LcgID6, bsr_l->LcgID5, bsr_l->LcgID4, + bsr_l->LcgID3, bsr_l->LcgID2, bsr_l->LcgID1, bsr_l->LcgID0); for (int n = 0; n < n_Lcg; n++){ LOG_D(NR_MAC, "LONG BSR, %d/%d (n/n_Lcg), BS Index %d, BS value < %d", @@ -322,14 +312,14 @@ int nr_process_mac_pdu(module_id_t module_idP, //38.321 section 6.1.3.2 //fixed length - mac_ce_len = 2; + mac_len = 2; /* Extract CRNTI value */ break; case UL_SCH_LCID_SINGLE_ENTRY_PHR: //38.321 section 6.1.3.8 //fixed length - mac_ce_len = 2; + mac_len = 2; /* Extract SINGLE ENTRY PHR elements for PHR calculation */ ce_ptr = &pduP[mac_subheader_len]; NR_SINGLE_ENTRY_PHR_MAC_CE *phr = (NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr; @@ -348,26 +338,11 @@ int nr_process_mac_pdu(module_id_t module_idP, break; case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT: - //38.321 section 6.1.3.9 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } - /* Extract MULTI ENTRY PHR elements from single octet bitmap for PHR calculation */ - break; - case UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT: - //38.321 section 6.1.3.9 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - } + // varialbe length + getMacLen(pduP, &mac_len, &mac_subheader_len); + //Extract MULTI ENTRY PHR elements from single octet bitmap for PHR calculation */ + break; /* Extract MULTI ENTRY PHR elements from four octets bitmap for PHR calculation */ break; @@ -378,23 +353,14 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_SRB1: case UL_SCH_LCID_SRB2: - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - //mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *) pduP)->L1 & 0x7f) << 8) - | ((uint16_t)((NR_MAC_SUBHEADER_LONG *) pduP)->L2 & 0xff); - } else { - mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - } - + getMacLen(pduP, &mac_len, &mac_subheader_len); rnti_t crnti = UE_info->rnti[UE_id]; int UE_idx = UE_id; for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[CC_id].ra[i]; if (ra->state >= WAIT_Msg3 && ra->rnti == UE_info->rnti[UE_id]) { - uint8_t *next_subpduP = pduP + mac_subheader_len + mac_sdu_len; - if ((pduP[mac_subheader_len+mac_sdu_len] & 0x3F) == UL_SCH_LCID_C_RNTI) { + uint8_t *next_subpduP = pduP + mac_subheader_len + mac_len; + if ((pduP[mac_subheader_len+mac_len] & 0x3F) == UL_SCH_LCID_C_RNTI) { crnti = ((next_subpduP[1]&0xFF)<<8)|(next_subpduP[2]&0xFF); UE_idx = find_nr_UE_id(module_idP, crnti); break; @@ -403,7 +369,7 @@ int nr_process_mac_pdu(module_id_t module_idP, } if (UE_info->CellGroup[UE_idx]) { - LOG_D(NR_MAC, "[UE %d] Frame %d : ULSCH -> UL-DCCH %d (gNB %d, %d bytes), rnti: 0x%04x \n", module_idP, frameP, rx_lcid, module_idP, mac_sdu_len, crnti); + LOG_D(NR_MAC, "[UE %d] Frame %d : ULSCH -> UL-DCCH %d (gNB %d, %d bytes), rnti: 0x%04x \n", module_idP, frameP, rx_lcid, module_idP, mac_len, crnti); mac_rlc_data_ind(module_idP, crnti, module_idP, @@ -412,7 +378,7 @@ int nr_process_mac_pdu(module_id_t module_idP, MBMS_FLAG_NO, rx_lcid, (char *) (pduP + mac_subheader_len), - mac_sdu_len, + mac_len, 1, NULL); } else { @@ -430,23 +396,23 @@ int nr_process_mac_pdu(module_id_t module_idP, if ( rx_lcid == UL_SCH_LCID_CCCH1 ) { // RRCResumeRequest1 message includes the full I-RNTI and has a size of 8 bytes - mac_sdu_len = 8; + mac_len = 8; // Check if it is a valid CCCH1 message, we get all 00's messages very often int i = 0; - for(i=0; i<(mac_subheader_len+mac_sdu_len); i++) { + for(i=0; i<(mac_subheader_len+mac_len); i++) { if(pduP[i] != 0) { break; } } - if (i == (mac_subheader_len+mac_sdu_len)) { + if (i == (mac_subheader_len+mac_len)) { LOG_D(NR_MAC, "%s() Invalid CCCH1 message!, pdu_len: %d\n", __func__, pdu_len); done = 1; break; } } else { // fixed length of 6 bytes - mac_sdu_len = 6; + mac_len = 6; } nr_mac_rrc_data_ind(module_idP, @@ -457,23 +423,12 @@ int nr_process_mac_pdu(module_id_t module_idP, UE_info->rnti[UE_id], CCCH, pduP + mac_subheader_len, - mac_sdu_len, + mac_len, 0); break; case UL_SCH_LCID_DTCH: - // check if LCID is valid at current time. - if (((NR_MAC_SUBHEADER_SHORT *)pduP)->F) { - // mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - mac_subheader_len = 3; - mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L1 & 0x7f) << 8) - | ((uint16_t)((NR_MAC_SUBHEADER_LONG *)pduP)->L2 & 0xff); - - } else { - mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - } - + getMacLen(pduP, &mac_len, &mac_subheader_len); LOG_D(NR_MAC, "In %s: [UE %d] %d.%d : ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", __func__, module_idP, @@ -482,8 +437,8 @@ int nr_process_mac_pdu(module_id_t module_idP, rx_lcid<4?"DCCH":"DTCH", rx_lcid, module_idP, - mac_sdu_len); - UE_info->mac_stats[UE_id].lc_bytes_rx[rx_lcid] += mac_sdu_len; + mac_len); + UE_info->mac_stats[UE_id].lc_bytes_rx[rx_lcid] += mac_len; mac_rlc_data_ind(module_idP, UE_info->rnti[UE_id], @@ -493,13 +448,13 @@ int nr_process_mac_pdu(module_id_t module_idP, MBMS_FLAG_NO, rx_lcid, (char *)(pduP + mac_subheader_len), - mac_sdu_len, + mac_len, 1, NULL); /* Updated estimated buffer when receiving data */ - if (sched_ctrl->estimated_ul_buffer >= mac_sdu_len) - sched_ctrl->estimated_ul_buffer -= mac_sdu_len; + if (sched_ctrl->estimated_ul_buffer >= mac_len) + sched_ctrl->estimated_ul_buffer -= mac_len; else sched_ctrl->estimated_ul_buffer = 0; break; @@ -514,16 +469,16 @@ int nr_process_mac_pdu(module_id_t module_idP, if (rx_lcid < 45 || rx_lcid == 52 || rx_lcid == 63) { LOG_I(NR_MAC, "In %s: dumping UL MAC SDU sub-header with length %d (LCID = 0x%02x):\n", __func__, mac_subheader_len, rx_lcid); log_dump(NR_MAC, pduP, mac_subheader_len, LOG_DUMP_CHAR, "\n"); - LOG_I(NR_MAC, "In %s: dumping UL MAC SDU with length %d (LCID = 0x%02x):\n", __func__, mac_sdu_len, rx_lcid); - log_dump(NR_MAC, pduP + mac_subheader_len, mac_sdu_len, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping UL MAC SDU with length %d (LCID = 0x%02x):\n", __func__, mac_len, rx_lcid); + log_dump(NR_MAC, pduP + mac_subheader_len, mac_len, LOG_DUMP_CHAR, "\n"); } else { - LOG_I(NR_MAC, "In %s: dumping UL MAC CE with length %d (LCID = 0x%02x):\n", __func__, mac_ce_len, rx_lcid); - log_dump(NR_MAC, pduP + mac_subheader_len + mac_sdu_len, mac_ce_len, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping UL MAC CE with length %d (LCID = 0x%02x):\n", __func__, mac_len, rx_lcid); + log_dump(NR_MAC, pduP + mac_subheader_len + mac_len, mac_len, LOG_DUMP_CHAR, "\n"); } #endif - pduP += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); - pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + pduP += ( mac_subheader_len + mac_len ); + pdu_len -= ( mac_subheader_len + mac_len ); if (pdu_len < 0) { LOG_E(NR_MAC, "In %s: residual UL MAC PDU in %d.%d with length < 0!, pdu_len %d \n", __func__, frameP, slot, pdu_len); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index eccffca031..eba9bc52b3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -444,7 +444,7 @@ typedef struct NR_UE_harq { /* Transport block to be sent using this HARQ process, its size is in * sched_pdsch */ - uint32_t tb[16384]; + uint32_t transportBlock[16384]; uint32_t tb_size; /// sched_pdsch keeps information on MCS etc used for the initial transmission diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 99897f9060..59cf465ac1 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -1065,7 +1065,7 @@ void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nac int nr_ue_ul_indication(nr_uplink_indication_t *ul_info){ - NR_UE_L2_STATE_t ret; + NR_UE_L2_STATE_t ret=0; module_id_t module_id = ul_info->module_id; NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 4492380d7f..c73c3d9649 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -969,9 +969,9 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( uint16_t ue_initial_id; uint32_t gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = NULL; - protocol_ctxt_t ctxt; - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp; + protocol_ctxt_t ctxt={0}; + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0}; + gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp={0}; uint8_t pdu_sessions_done; uint8_t inde_list[NR_NB_RB_MAX - 3]= {0}; int ret = 0; diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 283f3b7311..e151fec9b4 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -428,7 +428,7 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id) { size += 10; // encode the message - initialNasMsg->data = (Byte_t *)malloc(size * sizeof(Byte_t)); + initialNasMsg->data = malloc16_clear(size * sizeof(Byte_t)); registration_request_buf = initialNasMsg->data; initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data), size); diff --git a/targets/ARCH/rfsimulator/apply_channelmod.c b/targets/ARCH/rfsimulator/apply_channelmod.c index d7d3a68965..6e26120e29 100644 --- a/targets/ARCH/rfsimulator/apply_channelmod.c +++ b/targets/ARCH/rfsimulator/apply_channelmod.c @@ -52,7 +52,7 @@ either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes legacy: we regenerate each sub frame in UL, and each frame only in DL */ -void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig, +void rxAddInput( c16_t *input_sig, c16_t *after_channel_sig, int rxAnt, channel_desc_t *channelDesc, int nbSamples, @@ -73,7 +73,7 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si const int nbTx=channelDesc->nb_tx; for (int i=0; i<((int)nbSamples-dd); i++) { - struct complex16 *out_ptr=after_channel_sig+dd+i; + c16_t *out_ptr=after_channel_sig+dd+i; struct complexd rx_tmp= {0}; for (int txAnt=0; txAnt < nbTx; txAnt++) { @@ -87,7 +87,7 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si // but it is not very usefull // it would be better to split out each antenna in a separate flow // that will allow to mix ru antennas freely - struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize]; + c16_t tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize]; rx_tmp.r += tx16.r * channelModel[l].r - tx16.i * channelModel[l].i; rx_tmp.i += tx16.i * channelModel[l].r + tx16.r * channelModel[l].i; } //l diff --git a/targets/ARCH/rfsimulator/rfsimulator.h b/targets/ARCH/rfsimulator/rfsimulator.h index 292873032e..33583f2d32 100644 --- a/targets/ARCH/rfsimulator/rfsimulator.h +++ b/targets/ARCH/rfsimulator/rfsimulator.h @@ -25,8 +25,8 @@ #define __RFSIMULATOR_H double gaussZiggurat(double mean, double variance); void tableNor(unsigned long seed); -void rxAddInput( struct complex16 *input_sig, - struct complex16 *after_channel_sig, +void rxAddInput( c16_t *input_sig, + c16_t *after_channel_sig, int rxAnt, channel_desc_t *channelDesc, int nbSamples, diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 013e542689..0a05f2cbef 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -100,7 +100,7 @@ static telnetshell_vardef_t rfsimu_vardef[] = { }; pthread_mutex_t Sockmutex; -typedef struct complex16 sample_t; // 2*16 bits complex number +typedef c16_t sample_t; // 2*16 bits complex number typedef struct buffer_s { int conn_sock; @@ -495,7 +495,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi setblocking(conn_sock, notBlocking); allocCirBuf(t, conn_sock); LOG_I(HW,"A client connected, sending the current time\n"); - struct complex16 v= {0}; + c16_t v= {0}; void *samplesVoid[t->tx_num_channels]; for ( int i=0; i < t->tx_num_channels; i++) @@ -665,7 +665,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest // We send timestamp for nb samples required // assuming this should have been done earlier if a Tx would exist pthread_mutex_unlock(&Sockmutex); - struct complex16 v= {0}; + c16_t v= {0}; void *dummyS[t->tx_num_channels]; for ( int i=0; i < t->tx_num_channels; i++) @@ -728,7 +728,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest for (int a=0; achannel_model != NULL ) // apply a channel model - rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a], + rxAddInput( ptr->circularBuf, (c16_t *) samplesVoid[a], a, ptr->channel_model, nsamps, diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 13a09db5a3..1b59ba9b2b 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1941,7 +1941,7 @@ void write_dummy(PHY_VARS_UE *UE, openair0_timestamp timestamp) { // we have to write to tell explicitly to the eNB, else it will wait for us forever // we write the next subframe (always write in future of what we received) // - struct complex16 v= {0}; + c16_t v= {0}; void *samplesVoid[UE->frame_parms.nb_antennas_tx]; for ( int i=0; i < UE->frame_parms.nb_antennas_tx; i++) From 288c29da84fa2466ea4d503bbdbcce16e8528bf1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 18 Mar 2022 19:46:42 +0000 Subject: [PATCH 062/226] Apply review suggestions --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 14 +++++++------- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 12 ++++++------ openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index eda53e1c84..b8eaefedb1 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -287,8 +287,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (int aa=0;aanb_antennas_rx;aa++) { c16_t *r=(c16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; for (n=0;n<12;n++) { - xr[aa][l][n].r +=(int32_t)x_re[l][n]*r[n].r+(int32_t)x_im[l][n]*r[n].i; - xr[aa][l][n].i +=(int32_t)x_re[l][n]*r[n].i-(int32_t)x_im[l][n]*r[n].r; + xr[aa][l][n].r += (int32_t)x_re[l][n] * r[n].r + (int32_t)x_im[l][n] * r[n].i; + xr[aa][l][n].i += (int32_t)x_re[l][n] * r[n].i - (int32_t)x_im[l][n] * r[n].r; #ifdef DEBUG_NR_PUCCH_RX printf("x (%d,%d), r%d.%d (%d,%d), xr (%lld,%lld)\n", x_re[l][n],x_im[l][n],l2,re_offset[l],r[n].r,r[n].i,xr[aa][l][n].r,xr[aa][l][n].i); @@ -317,12 +317,12 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (int aa=0;aanb_antennas_rx;aa++) { corr_re[aa][l]=0; corr_im[aa][l]=0; - for (n=0;n<12;n++) { - corr_re[aa][l]+=xr[aa][l][n].r*idft12_re[seq_index][n]+xr[aa][l][n].i*idft12_im[seq_index][n]; - corr_im[aa][l]+=xr[aa][l][n].r*idft12_im[seq_index][n]-xr[aa][l][n].i*idft12_re[seq_index][n]; + for (n = 0; n < 12; n++) { + corr_re[aa][l] += xr[aa][l][n].r * idft12_re[seq_index][n] + xr[aa][l][n].i * idft12_im[seq_index][n]; + corr_im[aa][l] += xr[aa][l][n].r * idft12_im[seq_index][n] - xr[aa][l][n].i * idft12_re[seq_index][n]; } - corr_re[aa][l]>>=15; - corr_im[aa][l]>>=15; + corr_re[aa][l] >>= 15; + corr_im[aa][l] >>= 15; } } LOG_D(PHY,"PUCCH IDFT[%d/%d] = (%ld,%ld)=>%f\n", diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index f084cb2d63..248c30f26f 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -118,14 +118,14 @@ typedef struct { } __attribute__ ((__packed__)) NR_MAC_SUBHEADER_FIXED; static inline void getMacLen(uint8_t* pdu, uint16_t *mac_ce_len, uint16_t *mac_subheader_len) { - NR_MAC_SUBHEADER_SHORT *s=(NR_MAC_SUBHEADER_SHORT*) pdu; - NR_MAC_SUBHEADER_LONG *l=(NR_MAC_SUBHEADER_LONG*) pdu; + NR_MAC_SUBHEADER_SHORT *s = (NR_MAC_SUBHEADER_SHORT*) pdu; + NR_MAC_SUBHEADER_LONG *l = (NR_MAC_SUBHEADER_LONG*) pdu; if (s->F) { - *mac_subheader_len=sizeof(*l); - *mac_ce_len=ntohs(l->L); + *mac_subheader_len = sizeof(*l); + *mac_ce_len = ntohs(l->L); } else { - *mac_subheader_len=sizeof(*s); - *mac_ce_len=s->L; + *mac_subheader_len = sizeof(*s); + *mac_ce_len = s->L; } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 05313f388a..61a2902690 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2092,7 +2092,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, pucch->is_common = current_harq->is_common; current_harq->active = false; current_harq->ack_received = false; - LOG_D(PHY,"%d.%d Sent %d ack on harq pid %d\n", frame, slot, current_harq->ack, dl_harq_pid); + LOG_D(PHY,"%4d.%2d Sent %d ack on harq pid %d\n", frame, slot, current_harq->ack, dl_harq_pid); } } } @@ -3497,7 +3497,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) return; getMacLen(pduP, &mac_len, &mac_subheader_len); - LOG_D(NR_MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, gNB_index, mac_len); + LOG_D(NR_MAC, "[UE %d] %4d.%2d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, slot, rx_lcid, gNB_index, mac_len); #if defined(ENABLE_MAC_PAYLOAD_DEBUG) LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); From b153d2d1ee021116226707fbdef90b62b31126c0 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 24 Mar 2022 21:10:23 +0100 Subject: [PATCH 063/226] fix bug in nr_rate_matching --- openair1/PHY/CODING/nr_rate_matching.c | 97 ++++++++++++++------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index 29cba0a557..84e6615ed9 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -309,60 +309,71 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f) void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f) { - int16_t *e1,*e2,*e3,*e4,*e5,*e6,*e7; switch(Qm) { case 2: - e1=e+(E/2); - for (int j = 0,j2=0; j< E/2; j+=2,j2+=4){ - e[j] = f[j2]; - e1[j] = f[j2+1]; - e[j+1] = f[j2+2]; - e1[j+1] = f[j2+3]; + { + int16_t *e1=e+(E/2); + int16_t *end=f+E-4; + while( f Date: Fri, 25 Mar 2022 16:32:07 +0100 Subject: [PATCH 064/226] fix bug introduced in this branch --- openair1/PHY/CODING/nr_rate_matching.c | 2 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 60 +++++++++++--------------- openair1/PHY/TOOLS/tools_defs.h | 3 ++ 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index 84e6615ed9..29a1e363e9 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -307,7 +307,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f) void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f) -{ +{ switch(Qm) { case 2: diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index b8eaefedb1..06b3c6e9e7 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -272,7 +272,6 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, x_im[1] = table_5_2_2_2_2_Im[u[1]]; c64_t xr[frame_parms->nb_antennas_rx][pucch_pdu->nr_of_symbols][12] __attribute__((aligned(32))); - memset(xr, 0, sizeof(xr)); int64_t xrtmag=0,xrtmag_next=0; uint8_t maxpos=0; uint8_t index=0; @@ -287,72 +286,65 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (int aa=0;aanb_antennas_rx;aa++) { c16_t *r=(c16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; for (n=0;n<12;n++) { - xr[aa][l][n].r += (int32_t)x_re[l][n] * r[n].r + (int32_t)x_im[l][n] * r[n].i; - xr[aa][l][n].i += (int32_t)x_re[l][n] * r[n].i - (int32_t)x_im[l][n] * r[n].r; + xr[aa][l][n].r = (int32_t)x_re[l][n] * r[n].r + (int32_t)x_im[l][n] * r[n].i; + xr[aa][l][n].i = (int32_t)x_re[l][n] * r[n].i - (int32_t)x_im[l][n] * r[n].r; #ifdef DEBUG_NR_PUCCH_RX printf("x (%d,%d), r%d.%d (%d,%d), xr (%lld,%lld)\n", x_re[l][n],x_im[l][n],l2,re_offset[l],r[n].r,r[n].i,xr[aa][l][n].r,xr[aa][l][n].i); #endif } - xr[aa][l][n].r>>=15; - xr[aa][l][n].i>>=15; } } - int64_t corr_re[frame_parms->nb_antennas_rx][2]; - int64_t corr_im[frame_parms->nb_antennas_rx][2]; //int32_t no_corr = 0; int seq_index = 0; int64_t temp; for(i=0;inr_of_symbols;l++) { - seq_index = (pucch_pdu->initial_cyclic_shift+ - mcs[i]+ - gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index])%12; + c64_t corr[frame_parms->nb_antennas_rx][2]; + for (int aa=0;aanb_antennas_rx;aa++) { + for (int l=0;lnr_of_symbols;l++) { + seq_index = (pucch_pdu->initial_cyclic_shift+ + mcs[i]+ + gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index])%12; #ifdef DEBUG_NR_PUCCH_RX - printf("PUCCH symbol %d seq %d, seq_index %d, mcs %d\n",l,i,seq_index,mcs[i]); + printf("PUCCH symbol %d seq %d, seq_index %d, mcs %d\n",l,i,seq_index,mcs[i]); #endif - for (int aa=0;aanb_antennas_rx;aa++) { - corr_re[aa][l]=0; - corr_im[aa][l]=0; + corr[aa][l]=(c64_t){0}; for (n = 0; n < 12; n++) { - corr_re[aa][l] += xr[aa][l][n].r * idft12_re[seq_index][n] + xr[aa][l][n].i * idft12_im[seq_index][n]; - corr_im[aa][l] += xr[aa][l][n].r * idft12_im[seq_index][n] - xr[aa][l][n].i * idft12_re[seq_index][n]; + corr[aa][l].r += xr[aa][l][n].r * idft12_re[seq_index][n] + xr[aa][l][n].i * idft12_im[seq_index][n]; + corr[aa][l].i += xr[aa][l][n].r * idft12_im[seq_index][n] - xr[aa][l][n].i * idft12_re[seq_index][n]; } - corr_re[aa][l] >>= 15; - corr_im[aa][l] >>= 15; + corr[aa][l].r >>= 31; + corr[aa][l].i >>= 31; } } LOG_D(PHY,"PUCCH IDFT[%d/%d] = (%ld,%ld)=>%f\n", - mcs[i],seq_index,corr_re[0][0],corr_im[0][0], - 10*log10((double)corr_re[0][0]*corr_re[0][0] + (double)corr_im[0][0]*corr_im[0][0])); + mcs[i],seq_index,corr[0][0].r,corr[0][0].i, + 10*log10((double)squaredMod(corr[0][0]))); if (pucch_pdu->nr_of_symbols==2) LOG_D(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%ld,%ld)=>%f\n", - mcs[i],seq_index,corr_re[0][1],corr_im[0][1], - 10*log10((double)corr_re[0][1]*corr_re[0][1] + (double)corr_im[0][1]*corr_im[0][1])); + mcs[i],seq_index,corr[0][1].r,corr[0][1].i, + 10*log10((double)squaredMod(corr[0][1]))); if (pucch_pdu->freq_hop_flag == 0) { if (pucch_pdu->nr_of_symbols==1) {// non-coherent correlation temp=0; for (int aa=0;aanb_antennas_rx;aa++) - temp+=(int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0]; + temp+=squaredMod(corr[aa][0]); } else { - int64_t corr_re2=0; - int64_t corr_im2=0; temp=0; for (int aa=0;aanb_antennas_rx;aa++) { - corr_re2 = (int64_t)corr_re[aa][0]+corr_re[aa][1]; - corr_im2 = (int64_t)corr_im[aa][0]+corr_im[aa][1]; - // coherent combining of 2 symbols and then complex modulus for single-frequency case - temp+=corr_re2*corr_re2 + corr_im2*corr_im2; + c64_t corr2; + csum(corr2, corr[aa][0], corr[aa][1]); + // coherent combining of 2 symbols and then complex modulus for single-frequency case + temp+=corr2.r*corr2.r + corr2.i*corr2.i; } } } else if (pucch_pdu->freq_hop_flag == 1) { // full non-coherent combining of 2 symbols for frequency-hopping case temp=0; for (int aa=0;aanb_antennas_rx;aa++) - temp += (int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0] + (int64_t)corr_re[aa][1]*corr_re[aa][1] + (int64_t)corr_im[aa][1]*corr_im[aa][1]; + temp += squaredMod(corr[aa][0]) + squaredMod(corr[aa][1]); } else AssertFatal(1==0,"shouldn't happen\n"); @@ -364,9 +356,9 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->current_pucch0_stat0 = 0; int64_t temp2=0,temp3=0;; for (int aa=0;aanb_antennas_rx;aa++) { - temp2 += ((int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0]); + temp2 += squaredMod(corr[aa][0]); if (pucch_pdu->nr_of_symbols==2) - temp3 += ((int64_t)corr_re[aa][1]*corr_re[aa][1] + (int64_t)corr_im[aa][1]*corr_im[aa][1]); + temp3 += squaredMod(corr[aa][1]); } uci_stats->current_pucch0_stat0= dB_fixed64(temp2); if ( pucch_pdu->nr_of_symbols==2) diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 13ce9d85c7..c763ec6bac 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -63,6 +63,9 @@ typedef struct complex64 { int64_t r; int64_t i; } c64_t; + +#define squaredMod(a) ((a).r*(a).r+(a).i*(a).i) +#define csum(res, i1, i2) (res).r=(i1).r+(i2).r ; (res).i=(i1).i+(i2).i //cmult_sv.h /*!\fn void multadd_real_vector_complex_scalar(int16_t *x,int16_t *alpha,int16_t *y,uint32_t N) From 65d0318504147bfedbca10de248174d222cc4b4d Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 25 Mar 2022 17:52:44 +0100 Subject: [PATCH 065/226] using tbslbrm at mac also for ulsch as in scf spec --- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 6 +++++- openair1/PHY/CODING/coding_defs.h | 6 ++---- openair1/PHY/CODING/nr_rate_matching.c | 10 ++++------ openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 4 +--- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 6 ++---- openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 5 +---- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 4 +--- openair1/PHY/defs_gNB.h | 1 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 ++ 9 files changed, 19 insertions(+), 25 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index ee680f7fc7..def9af3e7a 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1200,6 +1200,10 @@ typedef struct #define PUSCH_PDU_BITMAP_PUSCH_PTRS 0x4 #define PUSCH_PDU_BITMAP_DFTS_OFDM 0x8 +typedef struct { + uint32_t tbSizeLbrmBytes; +}nfapi_v3_pusch_maintenance_parameters_t; + typedef struct { uint16_t pdu_bit_map;//Bitmap indicating presence of optional PDUs (see above) @@ -1245,7 +1249,7 @@ typedef struct nfapi_nr_dfts_ofdm_t dfts_ofdm; //beamforming nfapi_nr_ul_beamforming_t beamforming; - + nfapi_v3_pdsch_maintenance_parameters_t maintenance_parms_v3; } nfapi_nr_pusch_pdu_t; //for pucch_pdu: diff --git a/openair1/PHY/CODING/coding_defs.h b/openair1/PHY/CODING/coding_defs.h index f6aba66830..51cae1bd8c 100644 --- a/openair1/PHY/CODING/coding_defs.h +++ b/openair1/PHY/CODING/coding_defs.h @@ -485,8 +485,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f); void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f); -int nr_rate_matching_ldpc(uint8_t Ilbrm, - uint32_t Tbslbrm, +int nr_rate_matching_ldpc(uint32_t Tbslbrm, uint8_t BG, uint16_t Z, uint8_t *w, @@ -497,8 +496,7 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm, uint8_t rvidx, uint32_t E); -int nr_rate_matching_ldpc_rx(uint8_t Ilbrm, - uint32_t Tbslbrm, +int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm, uint8_t BG, uint16_t Z, int16_t *w, diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index 29cba0a557..a828230718 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -373,8 +373,7 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f) } -int nr_rate_matching_ldpc(uint8_t Ilbrm, - uint32_t Tbslbrm, +int nr_rate_matching_ldpc(uint32_t Tbslbrm, uint8_t BG, uint16_t Z, uint8_t *w, @@ -395,7 +394,7 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm, //Bit selection N = (BG==1)?(66*Z):(50*Z); - if (Ilbrm == 0) + if (Tbslbrm == 0) Ncb = N; else { Nref = 3*Tbslbrm/(2*C); //R_LBRM = 2/3 @@ -457,8 +456,7 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm, return 0; } -int nr_rate_matching_ldpc_rx(uint8_t Ilbrm, - uint32_t Tbslbrm, +int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm, uint8_t BG, uint16_t Z, int16_t *w, @@ -484,7 +482,7 @@ int nr_rate_matching_ldpc_rx(uint8_t Ilbrm, //Bit selection N = (BG==1)?(66*Z):(50*Z); - if (Ilbrm == 0) + if (Tbslbrm == 0) Ncb = N; else { Nref = (3*Tbslbrm/(2*C)); //R_LBRM = 2/3 diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 73bb9bd991..e9b1050156 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -242,12 +242,10 @@ void ldpc8blocks( void *p) { mod_order,nb_rb); uint32_t Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; - uint8_t Ilbrm = 1; uint8_t e[E]; bzero (e, E); - nr_rate_matching_ldpc(Ilbrm, - Tbslbrm, + nr_rate_matching_ldpc(Tbslbrm, impp->BG, *impp->Zc, impp->d[rr], diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 06cc2aaea8..5b33939a0d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -246,8 +246,6 @@ void nr_processULSegment(void* arg) { __m128i *pv = (__m128i*)&z; __m128i *pl = (__m128i*)&l; - - uint8_t Ilbrm = 0; Kr = ulsch_harq->K; Kr_bytes = Kr>>3; @@ -295,8 +293,7 @@ void nr_processULSegment(void* arg) { //start_meas(&phy_vars_gNB->ulsch_rate_unmatching_stats); - if (nr_rate_matching_ldpc_rx(Ilbrm, - 0, + if (nr_rate_matching_ldpc_rx(rdata->tbslbrm, p_decoderParms->BG, p_decoderParms->Z, ulsch_harq->d[r], @@ -594,6 +591,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, rdata->offset = offset; rdata->ulsch = ulsch; rdata->ulsch_id = ULSCH_id; + rdata->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes; pushTpool(phy_vars_gNB->threadPool,req); phy_vars_gNB->nbDecode++; LOG_D(PHY,"Added a block to decode, in pipe: %d\n",phy_vars_gNB->nbDecode); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 34081659ac..7b7eec3d63 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -292,8 +292,6 @@ void nr_processDLSegment(void* arg) { __m128i *pv = (__m128i*)&z; __m128i *pl = (__m128i*)&l; - uint8_t Ilbrm = 1; - Kr = harq_process->K; // [hna] overwrites this line "Kr = p_decParams->Z*kb" Kr_bytes = Kr>>3; K_bits_F = Kr-harq_process->F; @@ -329,8 +327,7 @@ void nr_processDLSegment(void* arg) { harq_process->round); */ //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); - if (nr_rate_matching_ldpc_rx(Ilbrm, - Tbslbrm, + if (nr_rate_matching_ldpc_rx(Tbslbrm, p_decoderParms->BG, p_decoderParms->Z, harq_process->d[r], diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index be51f1f8b2..5de615a0cc 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -188,7 +188,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, uint16_t Kr=0; uint32_t r_offset=0; uint32_t F=0; - uint8_t Ilbrm = 0; float Coderate = 0.0; /////////// @@ -378,8 +377,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN); start_meas(&ue->ulsch_rate_matching_stats); - if (nr_rate_matching_ldpc(Ilbrm, - 0, + if (nr_rate_matching_ldpc(0, harq_process->BG, *pz, harq_process->d[r], diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 8faf4a50ce..e19468ad1b 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -927,6 +927,7 @@ typedef struct LDPCDecode_s { int r_offset; int offset; int decodeIterations; + uint32_t tbslbrm; } ldpcDecode_t; struct ldpcReqId { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index aa49b14fe5..273ad0dd40 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1767,6 +1767,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size; pusch_pdu->pusch_data.num_cb = 0; //CBG not supported + pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = 0; + LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); /* TRANSFORM PRECODING --------------------------------------------------------*/ From 9be58373bc35b076b07f8bcc9d5aedb487956e5c Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 25 Mar 2022 18:20:05 +0100 Subject: [PATCH 066/226] fix regression on harq in UE --- openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 12 +++++++----- openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 1 + openair1/SIMULATION/NR_PHY/dlschsim.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 6163a95e5c..eac595b39e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -168,6 +168,8 @@ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint dlsch->harq_processes[i]->d[r] = (int16_t *)malloc16(5*8448*sizeof(int16_t)); if (dlsch->harq_processes[i]->c[r]) memset(dlsch->harq_processes[i]->c[r],0,1056); + if (dlsch->harq_processes[i]->d[r]) + memset(dlsch->harq_processes[i]->d[r],0,5*8448); else exit_flag=2; @@ -306,6 +308,7 @@ void nr_processDLSegment(void* arg) { //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); int16_t w[E]; + memset(w, 0, sizeof(w)); nr_deinterleaving_ldpc(E, Qm, w, // [hna] w is e @@ -324,12 +327,11 @@ void nr_processDLSegment(void* arg) { harq_process->rvidx, harq_process->round); */ //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); - int16_t d[5*8448]; if (nr_rate_matching_ldpc_rx(Ilbrm, Tbslbrm, p_decoderParms->BG, p_decoderParms->Z, - d, + harq_process->d[r], w, harq_process->C, harq_process->rvidx, @@ -351,7 +353,7 @@ void nr_processDLSegment(void* arg) { LOG_D(PHY,"decoder input(segment %u) :",r); for (int i=0; id[r][i]); LOG_D(PHY,"\n"); } @@ -377,9 +379,9 @@ void nr_processDLSegment(void* arg) { //set Filler bits memset((&z[0]+K_bits_F),127,harq_process->F*sizeof(int16_t)); //Move coded bits before filler bits - memcpy((&z[0]+2*harq_process->Z),d,(K_bits_F-2*harq_process->Z)*sizeof(int16_t)); + memcpy((&z[0]+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t)); //skip filler bits - memcpy((&z[0]+Kr),d+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t)); + memcpy((&z[0]+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t)); //Saturate coded bits before decoding into 8 bits values for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index f76119250f..ef42bb2abd 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -181,6 +181,7 @@ typedef struct { /// Pointers to transport block segments uint8_t **c; /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + /// Accumulates the soft bits for each round to increase decoding success (HARQ) int16_t **d; /// Index of current HARQ round for this DLSCH uint8_t round; diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index c8969d7a0f..eb48d26908 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -483,7 +483,7 @@ int main(int argc, char **argv) //unsigned char test_input[TBS / 8] __attribute__ ((aligned(16))); for (i = 0; i < TBS / 8; i++) test_input[i] = (unsigned char) rand(); - + harq->pdu=test_input; //estimated_output = harq_process->b; #ifdef DEBUG_NR_DLSCHSIM From a79ccb99926ab6e93e826a93441347436a6f5269 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 25 Mar 2022 21:45:37 +0100 Subject: [PATCH 067/226] fix nr_deinterleaving_ldpc() again, we are now too short in the buffer --- common/utils/assertions.h | 4 ++-- openair1/PHY/CODING/nr_rate_matching.c | 27 +++++++++++++++----------- openair1/SIMULATION/NR_PHY/dlschsim.c | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/common/utils/assertions.h b/common/utils/assertions.h index 573036b1d9..c8959d0adb 100644 --- a/common/utils/assertions.h +++ b/common/utils/assertions.h @@ -44,9 +44,9 @@ #define _Assert_(cOND, aCTION, fORMAT, aRGS...) \ do { \ if (!(cOND)) { \ - fprintf(stderr, "\nAssertion ("#cOND") failed!\n" \ + fprintf(stderr, "\nAssertion (%s) failed!\n" \ "In %s() %s:%d\n" fORMAT, \ - __FUNCTION__, __FILE__, __LINE__, ##aRGS); \ + #cOND, __FUNCTION__, __FILE__, __LINE__, ##aRGS); \ aCTION; \ } \ } while(0) diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index 29a1e363e9..fbad79cad7 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -309,25 +309,28 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f) void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f) { + switch(Qm) { case 2: { - int16_t *e1=e+(E/2); - int16_t *end=f+E-4; - while( fpdu=test_input; + dlsch->harq_process.pdu=test_input; //estimated_output = harq_process->b; #ifdef DEBUG_NR_DLSCHSIM From c0568a997a003b15b64e47c3ae8c4868d0630425 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 22 Mar 2022 15:23:44 +0100 Subject: [PATCH 068/226] fix bugs, delete dead code --- executables/nr-ue.c | 27 +++--- openair1/PHY/defs_RU.h | 1 - openair1/PHY/defs_UE.h | 14 --- openair1/PHY/defs_gNB.h | 3 - openair1/SCHED_UE/phy_procedures_lte_ue.c | 106 ---------------------- openair2/RRC/LTE/rrc_UE.c | 3 +- targets/ARCH/rfsimulator/simulator.c | 72 ++++----------- targets/RT/USER/lte-ru.c | 19 +++- targets/RT/USER/lte-softmodem.h | 1 - targets/RT/USER/lte-uesoftmodem.c | 9 -- 10 files changed, 51 insertions(+), 204 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 3cc71b8b3a..aef0370e53 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -654,17 +654,15 @@ static void UE_synch(void *arg) { openair0_cfg[UE->rf_map.card].rx_freq[0], openair0_cfg[UE->rf_map.card].tx_freq[0]); - if (UE->mode != loop_through_memory) { - UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); - //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]); - //UE->rfdevice.trx_stop_func(&UE->rfdevice); - // sleep(1); - /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { - LOG_E(HW,"Could not start the device\n"); - oai_exit=1; - }*/ - } - + UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); + //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]); + //UE->rfdevice.trx_stop_func(&UE->rfdevice); + // sleep(1); + /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { + LOG_E(HW,"Could not start the device\n"); + oai_exit=1; + }*/ + if (UE->UE_scan_carrier == 1) { UE->UE_scan_carrier = 0; } else { @@ -683,8 +681,7 @@ static void UE_synch(void *arg) { LOG_I(PHY, "Initial sync failed: trying carrier off %d Hz\n", freq_offset); - if (UE->mode != loop_through_memory) - UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); + UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); } break; @@ -729,7 +726,7 @@ void processSlotTX(void *arg) { stop_meas(&UE->ue_ul_indication_stats); } - if ((UE->mode != loop_through_memory) && (rxtxD->ue_sched_mode != NOT_PUSCH)) { + if (rxtxD->ue_sched_mode != NOT_PUSCH) { phy_procedures_nrUE_TX(UE,proc,0); } } @@ -873,7 +870,7 @@ void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms); for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) { int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ; - // we write before read becasue gNB waits for UE to write and both executions halt + // we write before read because gNB waits for UE to write and both executions halt // this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot if (IS_SOFTMODEM_RFSIM) dummyWrite(UE,*timestamp, unitTransfer); AssertFatal(unitTransfer == diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 0b20aa409b..243e76f851 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -54,7 +54,6 @@ typedef enum { no_L2_connect=5, calib_prach_tx=6, rx_dump_frame=7, - loop_through_memory=8 } runmode_t; /*! \brief Extension Type */ diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h index 7f4d07ddae..a634a0d585 100644 --- a/openair1/PHY/defs_UE.h +++ b/openair1/PHY/defs_UE.h @@ -168,19 +168,6 @@ typedef struct { struct sched_param sched_param_ue; /// pthread descriptor main UE thread pthread_t pthread_ue; - /// \brief Instance count for synch thread. - /// \internal This variable is protected by \ref mutex_synch. - int instance_cnt_synch; - /// pthread attributes for synch processing thread - pthread_attr_t attr_synch; - /// scheduling parameters for synch thread - struct sched_param sched_param_synch; - /// pthread descriptor synch thread - pthread_t pthread_synch; - /// condition variable for UE synch thread; - pthread_cond_t cond_synch; - /// mutex for UE synch thread - pthread_mutex_t mutex_synch; /// instance count for eNBs int instance_cnt_eNBs; /// set of scheduling variables RXn-TXnp4 threads @@ -833,7 +820,6 @@ typedef struct { pthread_mutex_t timer_mutex; pthread_cond_t timer_cond; int instance_cnt_timer; - /// RF and Interface devices per CC openair0_device rfdevice; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 6dcce5df0a..66bf3e8b03 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -589,9 +589,6 @@ typedef struct gNB_L1_proc_t_s { int instance_cnt_te; /// \internal This variable is protected by \ref mutex_prach. int instance_cnt_prach; - - // instance count for over-the-air gNB synchronization - int instance_cnt_synch; /// \internal This variable is protected by \ref mutex_asynch_rxtx. int instance_cnt_asynch_rxtx; /// pthread structure for eNB single processing thread diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index b02f24e04e..52e7351e24 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -4870,109 +4870,3 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue, LOG_D(PHY," ****** end RX-Chain for AbsSubframe %d.%d ****** \n", frame_rx%1024, subframe_rx); return (0); } - - -void phy_procedures_UE_lte(PHY_VARS_UE *ue, - UE_rxtx_proc_t *proc, - uint8_t eNB_id, - uint8_t abstraction_flag, - uint8_t do_pdcch_flag, - runmode_t mode) { - MessageDef *msg_p; - int result; - int frame_rx = proc->frame_rx; - int frame_tx = proc->frame_tx; - int subframe_rx = proc->subframe_rx; - int subframe_tx = proc->subframe_tx; - UE_L2_STATE_t ret; - int slot; - - if (ue->mac_enabled == 0) { - ue->UE_mode[eNB_id]=PUSCH; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE,1); - - if ( LOG_DEBUGFLAG(UE_TIMING)) { - start_meas(&ue->phy_proc[ue->current_thread_id[subframe_rx]]); - } - do { - // Checks if a message has been sent to PHY sub-task - itti_poll_msg (TASK_PHY_UE, &msg_p); - - if (msg_p != NULL) { - switch (ITTI_MSG_ID(msg_p)) { - case PHY_FIND_CELL_REQ: - LOG_I(PHY, "[UE ] Received %s\n", ITTI_MSG_NAME (msg_p)); - /* TODO process the message */ - break; - - default: - LOG_E(PHY, "[UE %ld] Received unexpected message %s\n", ITTI_MSG_DESTINATION_INSTANCE (msg_p), ITTI_MSG_NAME (msg_p)); - break; - } - - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - } - } while(msg_p != NULL); - - for (slot=0; slot<2; slot++) { - if ((subframe_select(&ue->frame_parms,subframe_tx)==SF_UL)|| - (ue->frame_parms.frame_type == FDD)) { - phy_procedures_UE_TX(ue,proc,eNB_id,abstraction_flag,mode); - } - - if ((subframe_select(&ue->frame_parms,subframe_rx)==SF_DL) || - (ue->frame_parms.frame_type == FDD)) { - phy_procedures_UE_RX(ue,proc,eNB_id,abstraction_flag,do_pdcch_flag,mode); - } - - if ((subframe_select(&ue->frame_parms,subframe_tx)==SF_S) && - (slot==1)) { - phy_procedures_UE_S_TX(ue,eNB_id,abstraction_flag); - } - - if ((subframe_select(&ue->frame_parms,subframe_rx)==SF_S) && - (slot==0)) { - phy_procedures_UE_RX(ue,proc,eNB_id,abstraction_flag,do_pdcch_flag,mode); - } - - if (ue->mac_enabled==1) { - if (slot==0) { - //LOG_I(PHY,"[UE %d] Frame %d, subframe %d, star ue_scheduler\n", ue->Mod_id,frame_rx,subframe_tx); - ret = ue_scheduler(ue->Mod_id, - frame_rx, - subframe_rx, - frame_tx, - subframe_tx, - subframe_select(&ue->frame_parms,subframe_tx), - eNB_id, - 0/*FIXME CC_id*/); - - if (ret == CONNECTION_LOST) { - LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",ue->Mod_id, - frame_rx,subframe_tx); - ue->UE_mode[eNB_id] = PRACH; - // mac_xface->macphy_exit("Connection lost"); - } else if (ret == PHY_RESYNCH) { - LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, trying to resynch\n", - ue->Mod_id, - frame_rx,subframe_tx); - ue->UE_mode[eNB_id] = RESYNCH; - // mac_xface->macphy_exit("Connection lost"); - } else if (ret == PHY_HO_PRACH) { - LOG_I(PHY,"[UE %d] Frame %d, subframe %d, return to PRACH and perform a contention-free access\n", - ue->Mod_id,frame_rx,subframe_tx); - ue->UE_mode[eNB_id] = PRACH; - } - } - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE,0); - - if (LOG_DEBUGFLAG(UE_TIMING)) { - stop_meas(&ue->phy_proc[ue->current_thread_id[subframe_rx]]); - } - } // slot -} diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index b46bba2492..9b37853ed2 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -3175,7 +3175,8 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const size_t num_plmn_data = sizeof(plmn_data) / sizeof(plmn_data[0]); for (size_t plmn_ind = 0;; ++plmn_ind) { if (plmn_ind == num_plmn_data) { - LOG_E( RRC, "Did not find name from internal table for %u %u\n", mcc, mnc); + LOG_W( RRC, "Did not find operator name from internal table for MCC %0*d, MNC %0*d\n", + mccdigits, mcc, mncdigits, mnc); break; } if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) { diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 013e542689..dc5eab2f34 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -117,7 +117,7 @@ typedef struct buffer_s { typedef struct { int listen_sock, epollfd; - openair0_timestamp nextTimestamp; + openair0_timestamp nextRxTstamp; openair0_timestamp lastWroteTS; uint64_t typeStamp; char *ip; @@ -196,7 +196,7 @@ static void removeCirBuf(rfsimulator_state_t *bridge, int sock) { free(bridge->buf[sock].circularBuf); // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented // a lot of mem leaks - free(bridge->buf[sock].channel_model); + //free(bridge->buf[sock].channel_model); memset(&bridge->buf[sock], 0, sizeof(buffer_t)); bridge->buf[sock].conn_sock=-1; } @@ -429,8 +429,6 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp if (!alreadyLocked) pthread_mutex_lock(&Sockmutex); - LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); - for (int i=0; ibuf[i]; @@ -549,14 +547,14 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi (t->typeStamp == ENB_MAGICDL && b->th.magic==UE_MAGICDL), "Socket Error in protocol"); b->headerMode=false; - if ( t->nextTimestamp == 0 ) { // First block in UE, resync with the eNB current TS - t->nextTimestamp=b->th.timestamp> nsamps_for_initial ? + if ( t->nextRxTstamp == 0 ) { // First block in UE, resync with the eNB current TS + t->nextRxTstamp=b->th.timestamp> nsamps_for_initial ? b->th.timestamp - nsamps_for_initial : 0; b->lastReceivedTS=b->th.timestamp> nsamps_for_initial ? b->th.timestamp : nsamps_for_initial; - LOG_W(HW,"UE got first timestamp: starting at %lu\n", t->nextTimestamp); + LOG_W(HW,"UE got first timestamp: starting at %lu\n", t->nextRxTstamp); b->trashingPacket=true; } else if ( b->lastReceivedTS < b->th.timestamp) { int nbAnt= b->th.nbAnt; @@ -623,7 +621,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } rfsimulator_state_t *t = device->priv; - LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps); + LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextRxTstamp+nsamps); // deliver data from received data // check if a UE is connected int first_sock; @@ -634,54 +632,22 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest if ( first_sock == FD_SETSIZE ) { // no connected device (we are eNB, no UE is connected) - if ( t->nextTimestamp == 0) + if ( t->nextRxTstamp == 0) LOG_W(HW,"No connected device, generating void samples...\n"); if (!flushInput(t, 10, nsamps)) { for (int x=0; x < nbAnt; x++) memset(samplesVoid[x],0,sampleToByte(nsamps,1)); - t->nextTimestamp+=nsamps; + t->nextRxTstamp+=nsamps; - if ( ((t->nextTimestamp/nsamps)%100) == 0) - LOG_D(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp); + if ( ((t->nextRxTstamp/nsamps)%100) == 0) + LOG_D(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextRxTstamp); - *ptimestamp = t->nextTimestamp-nsamps; + *ptimestamp = t->nextRxTstamp-nsamps; return nsamps; } } else { - pthread_mutex_lock(&Sockmutex); - - if ( t->nextTimestamp > 0 && t->lastWroteTS < t->nextTimestamp) { - pthread_mutex_unlock(&Sockmutex); - usleep(10000); - pthread_mutex_lock(&Sockmutex); - - if ( t->lastWroteTS < t->nextTimestamp ) { - // Assuming Tx is not done fully in another thread - // We can never write is the past from the received time - // So, the node perform receive but will never write these symbols - // let's tell this to the opposite node - // We send timestamp for nb samples required - // assuming this should have been done earlier if a Tx would exist - pthread_mutex_unlock(&Sockmutex); - struct complex16 v= {0}; - void *dummyS[t->tx_num_channels]; - - for ( int i=0; i < t->tx_num_channels; i++) - dummyS[i]=(void *)&v; - - LOG_I(HW, "No samples Tx occured, so we send 1 sample to notify it: Tx:%lu, Rx:%lu\n", - t->lastWroteTS, t->nextTimestamp); - rfsimulator_write_internal(t, t->nextTimestamp, - dummyS, 1, - t->tx_num_channels, 1, true); - } else { - pthread_mutex_unlock(&Sockmutex); - LOG_W(HW, "trx_write came from another thread\n"); - } - } else - pthread_mutex_unlock(&Sockmutex); bool have_to_wait; @@ -692,7 +658,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest buffer_t *b=&t->buf[sock]; if ( b->circularBuf ) - if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) { + if ( t->nextRxTstamp+nsamps > b->lastReceivedTS ) { have_to_wait=true; break; } @@ -701,7 +667,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest if (have_to_wait) /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n", ptr->lastReceivedTS, - t->nextTimestamp+nsamps); + t->nextRxTstamp+nsamps); */ flushInput(t, 3, nsamps); } while (have_to_wait); @@ -732,7 +698,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest a, ptr->channel_model, nsamps, - t->nextTimestamp, + t->nextRxTstamp, CirSize ); else { // no channel modeling @@ -747,8 +713,8 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest //LOG_I(HW, "nbAnt_tx %d\n",nbAnt_tx); for (int i=0; i < nsamps; i++) {//loop over nsamps for (int a_tx=0; a_txcircularBuf[((t->nextTimestamp+i)*nbAnt_tx+a_tx)%CirSize].r*H_awgn_mimo[a][a_tx]); - out[i].i += (short)(ptr->circularBuf[((t->nextTimestamp+i)*nbAnt_tx+a_tx)%CirSize].i*H_awgn_mimo[a][a_tx]); + out[i].r += (short)(ptr->circularBuf[((t->nextRxTstamp+i)*nbAnt_tx+a_tx)%CirSize].r*H_awgn_mimo[a][a_tx]); + out[i].i += (short)(ptr->circularBuf[((t->nextRxTstamp+i)*nbAnt_tx+a_tx)%CirSize].i*H_awgn_mimo[a][a_tx]); } // end for a_tx } // end for i (number of samps) } // end of no channel modeling @@ -756,11 +722,11 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } } - *ptimestamp = t->nextTimestamp; // return the time of the first sample - t->nextTimestamp+=nsamps; + *ptimestamp = t->nextRxTstamp; // return the time of the first sample + t->nextRxTstamp+=nsamps; LOG_D(HW,"Rx to upper layer: %d from %ld to %ld, energy in first antenna %d\n", nsamps, - *ptimestamp, t->nextTimestamp, + *ptimestamp, t->nextRxTstamp, signal_energy(samplesVoid[0], nsamps)); return nsamps; } diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 66ce6ef247..f6cf51f101 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -733,7 +733,7 @@ void tx_rf(RU_t *ru, int sf_extension = 0; if ((SF_type == SF_DL) || - (SF_type == SF_S)) { + (SF_type == SF_S) ) { int siglen=fp->samples_per_tti,flags=1; if (SF_type == SF_S) { @@ -831,6 +831,23 @@ void tx_rf(RU_t *ru, late_control=STATE_BURST_TERMINATE; LOG_E(PHY,"TX : Timeout (sent %d/%d) state =%d\n",txs, siglen,late_control); } + } else if (IS_SOFTMODEM_RFSIM ) { + // in case of rfsim, we always enable tx because we need to feed rx of the opposite side + // we write 1 single I/Q sample to trigger Rx (rfsim will fill gaps with 0 I/Q) + void *dummy_tx[ru->frame_parms->nb_antennas_tx]; + for (int i=0; iframe_parms->nb_antennas_tx; i++) + dummy_tx[i]=malloc16_clear(4); + + AssertFatal( 1 == + ru->rfdevice.trx_write_func(&ru->rfdevice, + timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + dummy_tx, + 1, + ru->frame_parms->nb_antennas_tx, + 4),""); + + for (int i=0; iframe_parms->nb_antennas_tx; i++) + free(dummy_tx[i]); } } diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 0267ad8ce0..1c887dd3c8 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -49,7 +49,6 @@ {"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ {"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ {"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ - {"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \ {"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \ } #define CMDLINE_CALIBUERX_IDX 0 diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 8cdef647ca..089941c7df 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -276,7 +276,6 @@ uint16_t node_number; static void get_options(void) { int CC_id=0; int tddflag=0; - char *loopfile=NULL; int dumpframe=0; int timingadv=0; uint8_t nfapi_mode = NFAPI_MONOLITHIC; @@ -293,14 +292,6 @@ static void get_options(void) { config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL); nfapi_setmode(nfapi_mode); - - if (loopfile != NULL) { - printf("Input file for hardware emulation: %s",loopfile); - mode=loop_through_memory; - input_fd = fopen(loopfile,"r"); - AssertFatal(input_fd != NULL,"Please provide a valid input file\n"); - } - get_softmodem_params()->hw_timing_advance = timingadv; if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue; From 9bd16f3c664af14b3d8f2184c91a698cef6ce1b8 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 28 Mar 2022 21:45:50 +0200 Subject: [PATCH 069/226] - fix for CSI-RS allocation (slot slot 0 in symbol 13, SIB1 10 symbols instead of 12 by default) - extra logging for CRNTI procedure (to catch bug in nr_free_list --- openair2/GNB_APP/gnb_paramdef.h | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 11 ++++++++++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 4 ++-- openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 5 +++-- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 28aa60d54b..e5f15969ac 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -146,7 +146,7 @@ typedef enum { {GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET, NULL, 0, iptr:NULL, defintval:31, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_PDSCHANTENNAPORTS, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_PUSCHANTENNAPORTS, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ -{GNB_CONFIG_STRING_SIB1TDA, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_SIB1TDA, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_DOCSIRS, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_DOSRS, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index d2f726e0fc..b9615eb99d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2015,7 +2015,16 @@ void remove_nr_list(NR_list_t *listP, int id) prev = cur; cur = &listP->next[*cur]; } - AssertFatal(*cur != -1, "ID %d not found in UE_list\n", id); + if (*cur == -1) { + cur = &listP->head; + prev=&listP->head; + while (*cur != -1 && *cur != id) { + LOG_I(NR_MAC,"remove_nr_list : id %d, *cur %d\n",id,*cur); + prev = cur; + cur = &listP->next[*cur]; + } + AssertFatal(1==0, "ID %d not found in UE_list\n", id); + } int *next = &listP->next[*cur]; *cur = listP->next[*cur]; *next = -1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 30d484ae08..1a66f336c8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -679,11 +679,11 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, UE_scheduling_control->ta_update = timing_advance; UE_scheduling_control->raw_rssi = rssi; UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640; - LOG_D(NR_MAC, "[UE %d] PUSCH TPC %d and TA %d\n",UE_id,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); + LOG_D(NR_MAC, "[UE %d] PUSCH TPC %d(SNRx10 %d) and TA %d\n",UE_id,UE_scheduling_control->tpc0,UE_scheduling_control->pusch_snrx10,UE_scheduling_control->ta_update); } else{ LOG_D(NR_MAC,"[UE %d] Detected DTX : increasing UE TX power\n",UE_id); - UE_scheduling_control->tpc0 = 3; + UE_scheduling_control->tpc0 = 1; } #if defined(ENABLE_MAC_PAYLOAD_DEBUG) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index 62aa101a50..007750c9fe 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -108,7 +108,7 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, if (rcvd_count < entity->rx_deliv || nr_pdcp_sdu_in_list(entity->rx_list, rcvd_count)) { - LOG_W(PDCP, "discard NR PDU rcvd_count=%d\n", rcvd_count); + LOG_W(PDCP, "discard NR PDU rcvd_count=%d, entity->rx_deliv %d,sdu_in_list %d\n", rcvd_count,entity->rx_deliv,nr_pdcp_sdu_in_list(entity->rx_list,rcvd_count)); return; } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 02c42b4e5f..18e4d76075 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1039,7 +1039,8 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, default: AssertFatal(1==0,"Number of ports not yet supported\n"); } - resourceMapping.firstOFDMSymbolInTimeDomain = 6; + // This programs CSI-RS in slot 0 symbol 13. Note: need to use a SIB1 configuration which leaves the last symbol free for CSI-RS. + resourceMapping.firstOFDMSymbolInTimeDomain = 13; resourceMapping.firstOFDMSymbolInTimeDomain2 = NULL; resourceMapping.density.present = NR_CSI_RS_ResourceMapping__density_PR_one; resourceMapping.density.choice.one = (NULL_t)0; @@ -1052,7 +1053,7 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, nzpcsi0->scramblingID = *servingcellconfigcommon->physCellId; nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset)); nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; - nzpcsi0->periodicityAndOffset->choice.slots320 = 20; + nzpcsi0->periodicityAndOffset->choice.slots320 = 0; nzpcsi0->qcl_InfoPeriodicCSI_RS = calloc(1,sizeof(*nzpcsi0->qcl_InfoPeriodicCSI_RS)); *nzpcsi0->qcl_InfoPeriodicCSI_RS=0; ASN_SEQUENCE_ADD(&csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list,nzpcsi0); From 10b4f4331e940131fae968bfa7071f2c8a8e8eaa Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 29 Mar 2022 23:10:08 +0200 Subject: [PATCH 070/226] CQI report in slots 7/27 --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 18e4d76075..9854398501 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1598,7 +1598,7 @@ void fill_initial_SpCellConfig(int uid, csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic)); csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (8 + (20 * uid)) % 320; + csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (7 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep1->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep1->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI; csirep1->reportQuantity.choice.cri_RI_PMI_CQI=(NULL_t)0; @@ -1657,7 +1657,7 @@ void fill_initial_SpCellConfig(int uid, csirep2->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep2->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep2->reportConfigType.choice.periodic)); csirep2->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (28 + (20 * uid)) % 320; + csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (27 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep2->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep2->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep2->reportQuantity.choice.cri_RSRP=(NULL_t)0; From 665db19ed6d2c1330c6be343486c3e3c0fa14c6a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 30 Mar 2022 17:25:37 +0200 Subject: [PATCH 071/226] Change first SA test to DDSUU 2.5ms TDD period + ping to 10ms --- ...nd78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf | 305 ++++++++++++++++++ ci-scripts/xml_files/fr1_sa_quectel.xml | 8 +- 2 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf new file mode 100644 index 0000000000..6fd04bf569 --- /dev/null +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf @@ -0,0 +1,305 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_CU_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({ + mcc = 208; + mnc = 97; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + sd = 0x010203; // 0 false, else true + }, + { + sst = 1; + sd = 0x112233; // 0 false, else true + } + ); + }); + + nr_cellid = 12345678L + +# tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 2; + ul_prbblacklist = "51,52,53,54" + do_SRS = 1; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3301.68 MHz + 22*12*30e-3 MHz = 3309.6 + #absoluteFrequencySSB = 620640; + # this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68 + absoluteFrequencySSB = 621312; + # this is 3503.28 MHz + 22*12*30e-3 MHz = 3511.2 + #absoluteFrequencySSB = 634080; + # this is 3600.48 MHz + #absoluteFrequencySSB = 640032; + #dl_frequencyBand = 78; + # this is 3301.68 MHz + #dl_absoluteFrequencyPointA = 620112; + # this is 3300.60 MHz + dl_absoluteFrequencyPointA = 620040; + # this is 3502.56 MHz + #dl_absoluteFrequencyPointA = 633552; + # this is 3600.48 MHz + #dl_absoluteFrequencyPointA = 640032; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=106 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -104; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 2; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "CI_GNB_IP_ADDR"; + GNB_INTERFACE_NAME_FOR_NGU = "em1"; + GNB_IPV4_ADDRESS_FOR_NGU = "CI_GNB_IP_ADDR"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; +# pusch_TargetSNRx10 = 200; +# pucch_TargetSNRx10 = 150; + ulsch_max_frame_inactivity = 0; + } +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + thread_pool_size = 8; + prach_dtx_threshold = 120; +# pucch0_dtx_threshold = 150; +} +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000]; + ##beamforming 1x4 matrix: 1 layer x 4 antennas + #bf_weights = [0x00007fff, 0x0000,0x0000, 0x0000]; + ## beamforming 2x2 matrix: + # bf_weights = [0x00007fff, 0x00000000, 0x00000000, 0x00007fff]; + ## beamforming 4x4 matrix: + #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; + sf_extension = 0 + sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sl_ahead = 5; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + f1ap_log_level ="debug"; + }; diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml index 8d15015c07..69399597c1 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel.xml @@ -22,7 +22,7 @@ --> TEST-SA-FR1-Tab1 - SA Ping DL UL with QUECTEL + SA Ping DL UL with Quectel, 2.5ms TDD tasks 1 @@ -63,7 +63,7 @@ Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf --sa -q --usrp-tx-thread-config 1 --T_stdout 2 --log_config.global_log_options level,nocolor,time + -O ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf --sa -q --usrp-tx-thread-config 1 --T_stdout 2 --log_config.global_log_options level,nocolor,time 0 0 nr @@ -92,7 +92,7 @@ nrmodule2_quectel -c 40 1 - 20 + 10 @@ -101,7 +101,7 @@ nrmodule2_quectel -c 100 -i 0,2 1 - 20 + 10 From 0152e8ce38027fb54fc7e5386253ff88bcd62c53 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 3 Apr 2022 20:26:05 +0200 Subject: [PATCH 072/226] fix dlsim compilation error --- openair1/SIMULATION/NR_PHY/dlsim.c | 5 ++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index fdd0d2295e..b9c74c6337 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -207,10 +207,9 @@ int nr_derive_key(int alg_type, uint8_t alg_id, void config_common(int Mod_idP, int ssb_SubcarrierOffset, - rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, + int pdsch_AntennaPorts, int pusch_AntennaPorts, - NR_ServingCellConfigCommon_t *scc - ); + NR_ServingCellConfigCommon_t *scc); int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index c1845b6555..0c780cd839 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -42,8 +42,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts, int pusch_AntennaPorts, - NR_ServingCellConfigCommon_t *scc - ); + NR_ServingCellConfigCommon_t *scc); int rrc_mac_config_req_gNB(module_id_t Mod_idP, int ssb_SubcarrierOffset, From f2e6537195b2bb553f291c914923da0f7a9f8ecf Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Sun, 10 Apr 2022 22:11:37 +0200 Subject: [PATCH 073/226] roolback regression --- openair1/PHY/defs_UE.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h index a634a0d585..4f9bc076ff 100644 --- a/openair1/PHY/defs_UE.h +++ b/openair1/PHY/defs_UE.h @@ -168,6 +168,19 @@ typedef struct { struct sched_param sched_param_ue; /// pthread descriptor main UE thread pthread_t pthread_ue; + /// \brief Instance count for synch thread. + /// \internal This variable is protected by \ref mutex_synch. + int instance_cnt_synch; + /// pthread attributes for synch processing thread + pthread_attr_t attr_synch; + /// scheduling parameters for synch thread + struct sched_param sched_param_synch; + /// pthread descriptor synch thread + pthread_t pthread_synch; + /// condition variable for UE synch thread; + pthread_cond_t cond_synch; + /// mutex for UE synch thread + pthread_mutex_t mutex_synch; /// instance count for eNBs int instance_cnt_eNBs; /// set of scheduling variables RXn-TXnp4 threads From b860d76cd62ecdb1dba5d8743482cd92c3a2f09e Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 11 Apr 2022 09:39:16 +0200 Subject: [PATCH 074/226] fix lte-ue.c main loop with 5G common vars --- targets/RT/USER/lte-ue.c | 1003 ++++++++++++++++++-------------------- 1 file changed, 482 insertions(+), 521 deletions(-) diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 9010a40bf9..8565e36e87 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -87,7 +87,7 @@ extern void multicast_link_start(void (*rx_handlerP) (unsigned int, char *), extern int multicast_link_write_sock(int groupP, char *dataP, uint32_t sizeP); -int tx_req_num_elems; +int tx_req_num_elems; extern uint16_t sf_ahead; //extern int tx_req_UE_MAC1(); @@ -176,6 +176,7 @@ PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, { PHY_VARS_UE *ue = (PHY_VARS_UE *)calloc(1,sizeof(PHY_VARS_UE)); AssertFatal(ue,""); + if (frame_parms!=(LTE_DL_FRAME_PARMS *)NULL) { // if we want to give initial frame parms, allocate the PHY_VARS_UE structure and put them in memcpy(&(ue->frame_parms), frame_parms, sizeof(LTE_DL_FRAME_PARMS)); } @@ -204,8 +205,7 @@ void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, - char *name) -{ + char *name) { #ifdef DEADLINE_SCHEDULER if (sched_runtime!=0) { @@ -266,8 +266,7 @@ void init_UE(int nb_inst, runmode_t mode, int rxgain, int txpowermax, - LTE_DL_FRAME_PARMS *fp0) -{ + LTE_DL_FRAME_PARMS *fp0) { PHY_VARS_UE *UE; int inst; int ret; @@ -283,9 +282,7 @@ void init_UE(int nb_inst, if (PHY_vars_UE_g[inst]==NULL) PHY_vars_UE_g[inst] = (PHY_VARS_UE **)calloc(1+MAX_NUM_CCs,sizeof(PHY_VARS_UE *)); LOG_I(PHY,"Allocating UE context %d\n",inst); - PHY_vars_UE_g[inst][0] = init_ue_vars(fp0,inst,0); - // turn off timing control loop in UE PHY_vars_UE_g[inst][0]->no_timing_correction = timing_correction; UE = PHY_vars_UE_g[inst][0]; @@ -362,7 +359,6 @@ void init_UE(int nb_inst, LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]); init_UE_threads(inst); - ret = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]); if (ret !=0) { @@ -385,8 +381,7 @@ void init_UE(int nb_inst, void init_UE_stub_single_thread(int nb_inst, int eMBMS_active, int uecap_xer_in, - char *emul_iface) -{ + char *emul_iface) { int inst; LOG_I(PHY,"UE : Calling Layer 2 for initialization, nb_inst: %d \n", nb_inst); l2_init_ue(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL, @@ -411,24 +406,23 @@ void init_UE_stub_single_thread(int nb_inst, } } -void init_UE_standalone_thread(int ue_idx) -{ +void init_UE_standalone_thread(int ue_idx) { int standalone_tx_port = 3211 + ue_idx * 2; int standalone_rx_port = 3212 + ue_idx * 2; ue_init_standalone_socket(standalone_tx_port, standalone_rx_port); - pthread_t thread; + if (pthread_create(&thread, NULL, ue_standalone_pnf_task, NULL) != 0) { LOG_E(MAC, "pthread_create failed for calling ue_standalone_pnf_task"); } + pthread_setname_np(thread, "oai:ue-stand"); } void init_UE_stub(int nb_inst, int eMBMS_active, int uecap_xer_in, - char *emul_iface) -{ + char *emul_iface) { int inst; LOG_I(PHY,"UE : Calling Layer 2 for initialization\n"); l2_init_ue(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL, @@ -462,8 +456,7 @@ void init_UE_stub(int nb_inst, * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -static void *UE_thread_synch(void *arg) -{ +static void *UE_thread_synch(void *arg) { static int UE_thread_synch_retval; int i ; PHY_VARS_UE *UE = (PHY_VARS_UE *) arg; @@ -478,6 +471,7 @@ static void *UE_thread_synch(void *arg) printf("UE_thread_sync in with PHY_vars_UE %p\n",arg); cpu_set_t cpuset; CPU_ZERO(&cpuset); + if ( threads.sync != -1 ) CPU_SET(threads.sync, &cpuset); @@ -757,8 +751,7 @@ static void *UE_thread_synch(void *arg) * \param arg is a pointer to a \ref PHY_VARS_UE structure. * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -const char *get_connectionloss_errstr(int errcode) -{ +const char *get_connectionloss_errstr(int errcode) { switch (errcode) { case CONNECTION_LOST: return "RRC Connection lost, returning to PRACH"; @@ -773,8 +766,7 @@ const char *get_connectionloss_errstr(int errcode) return "UNKNOWN RETURN CODE"; } -static void *UE_thread_rxn_txnp4(void *arg) -{ +static void *UE_thread_rxn_txnp4(void *arg) { static __thread int UE_thread_rxtx_retval; struct rx_tx_thread_data *rtd = arg; UE_rxtx_proc_t *proc = rtd->proc; @@ -867,13 +859,11 @@ static void *UE_thread_rxn_txnp4(void *arg) if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || (UE->frame_parms.frame_type == FDD) ) - if (UE->mode != loop_through_memory) - phy_procedures_UE_TX(UE,proc,0,0,UE->mode); + phy_procedures_UE_TX(UE,proc,0,0,UE->mode); if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) && (UE->frame_parms.frame_type == TDD)) - if (UE->mode != loop_through_memory) - phy_procedures_UE_S_TX(UE,0,0); + phy_procedures_UE_S_TX(UE,0,0); proc->instance_cnt_rxtx--; @@ -895,8 +885,7 @@ static void *UE_thread_rxn_txnp4(void *arg) unsigned int emulator_absSF; void ue_stub_rx_handler(unsigned int num_bytes, - char *rx_buffer) -{ + char *rx_buffer) { PHY_VARS_UE *UE; UE = PHY_vars_UE_g[0][0]; UE_tport_t *pdu = (UE_tport_t *)rx_buffer; @@ -951,14 +940,14 @@ void ue_stub_rx_handler(unsigned int num_bytes, } } -uint64_t clock_usec(void) -{ - struct timespec t; - if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) - { - abort(); - } - return (uint64_t)t.tv_sec * 1000000 + (t.tv_nsec / 1000); +uint64_t clock_usec(void) { + struct timespec t; + + if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) { + abort(); + } + + return (uint64_t)t.tv_sec * 1000000 + (t.tv_nsec / 1000); } /*! * \brief This is the UE thread for RX subframe n and TX subframe n+4. @@ -968,23 +957,21 @@ uint64_t clock_usec(void) * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -static void *UE_phy_stub_standalone_pnf_task(void *arg) -{ +static void *UE_phy_stub_standalone_pnf_task(void *arg) { #if 1 { struct sched_param sparam = { .sched_priority = 79, }; - if (pthread_setschedparam(pthread_self(), SCHED_RR, &sparam) != 0) - { + + if (pthread_setschedparam(pthread_self(), SCHED_RR, &sparam) != 0) { LOG_E(PHY,"pthread_setschedparam: %s\n", strerror(errno)); } } #else thread_top_init("UE_phy_stub_thread_rxn_txnp4", 1, 870000L, 1000000L, 1000000L); #endif - // for multipule UE's L2-emulator //module_id_t Mod_id = 0; //int init_ra_UE = -1; // This counter is used to initiate the RA of each UE in different SFrames @@ -1004,9 +991,7 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) PHY_VARS_UE *UE = NULL; int ret; proc = &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0]; - UE = rtd->UE; - UL_INFO = (UL_IND_t *)calloc(1, sizeof(UL_IND_t)); UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = calloc(NFAPI_RX_IND_MAX_PDU, sizeof(nfapi_rx_indication_pdu_t)); UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; @@ -1019,19 +1004,15 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = calloc(NFAPI_CQI_IND_MAX_PDU, sizeof(nfapi_cqi_indication_pdu_t)); UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = calloc(NFAPI_CQI_IND_MAX_PDU, sizeof(nfapi_cqi_indication_raw_pdu_t)); UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; - proc->subframe_rx = proc->sub_frame_start; proc->subframe_tx = -1; proc->frame_rx = -1; proc->frame_tx = -1; // Initializations for nfapi-L2-emulator mode sync_var = 0; - //PANOS: CAREFUL HERE! wait_sync("UE_phy_stub_standalone_pnf_task"); - int last_sfn_sf = -1; - LOG_I(MAC, "Clearing Queues\n"); reset_queue(&dl_config_req_tx_req_queue); reset_queue(&ul_config_req_queue); @@ -1039,72 +1020,77 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) while (!oai_exit) { bool sent_any = false; + if (sem_wait(&sfn_semaphore) != 0) { LOG_E(MAC, "sem_wait() error\n"); abort(); } int sfn_sf = current_sfn_sf; - if (sfn_sf == last_sfn_sf) - { + + if (sfn_sf == last_sfn_sf) { LOG_W(MAC, "repeated sfn_sf = %d.%d\n", sfn_sf >> 4, sfn_sf & 15); continue; } - last_sfn_sf = sfn_sf; + last_sfn_sf = sfn_sf; nfapi_dl_config_req_tx_req_t *dl_config_req_tx_req = get_queue(&dl_config_req_tx_req_queue); nfapi_ul_config_request_t *ul_config_req = get_queue(&ul_config_req_queue); nfapi_hi_dci0_request_t *hi_dci0_req = get_queue(&hi_dci0_req_queue); - LOG_I(MAC, "received from proxy frame %d subframe %d\n", NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); if (ul_config_req != NULL) { uint8_t ul_num_pdus = ul_config_req->ul_config_request_body.number_of_pdus; + if (ul_num_pdus > 0) { char *ul_str = nfapi_ul_config_req_to_string(ul_config_req); LOG_I(MAC, "ul_config_req: %s\n", ul_str); free(ul_str); } } + if (hi_dci0_req != NULL) { LOG_D(MAC, "hi_dci0_req pdus: %u Frame: %d Subframe: %d\n", - hi_dci0_req->hi_dci0_request_body.number_of_dci, - NFAPI_SFNSF2SFN(hi_dci0_req->sfn_sf), NFAPI_SFNSF2SF(hi_dci0_req->sfn_sf)); + hi_dci0_req->hi_dci0_request_body.number_of_dci, + NFAPI_SFNSF2SFN(hi_dci0_req->sfn_sf), NFAPI_SFNSF2SF(hi_dci0_req->sfn_sf)); } if (dl_config_req_tx_req != NULL) { - nfapi_tx_req_pdu_list_t *tx_req_pdu_list = dl_config_req_tx_req->tx_req_pdu_list; nfapi_dl_config_request_t *dl_config_req = dl_config_req_tx_req->dl_config_req; - uint16_t dl_num_pdus = dl_config_req->dl_config_request_body.number_pdu; LOG_I(MAC, "(OAI UE) Received dl_config_req from proxy at Frame: %d, Subframe: %d," " with number of PDUs: %u\n", NFAPI_SFNSF2SFN(dl_config_req->sfn_sf), NFAPI_SFNSF2SF(dl_config_req->sfn_sf), dl_num_pdus); + if (dl_num_pdus > 0) { char *dl_str = nfapi_dl_config_req_to_string(dl_config_req); LOG_I(MAC, "dl_config_req: %s\n", dl_str); free(dl_str); } - LOG_D(MAC, "tx_req pdus: %d\n", tx_req_pdu_list->num_pdus); + LOG_D(MAC, "tx_req pdus: %d\n", tx_req_pdu_list->num_pdus); // Handling dl_config_req and tx_req: nfapi_dl_config_request_body_t *dl_config_req_body = &dl_config_req->dl_config_request_body; + for (int i = 0; i < dl_config_req_body->number_pdu; ++i) { nfapi_dl_config_request_pdu_t *pdu = &dl_config_req_body->dl_config_pdu_list[i]; + if (pdu->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) { i += 1; AssertFatal(i < dl_config_req->dl_config_request_body.number_pdu, "Need PDU following DCI at index %d, but not found\n", i); nfapi_dl_config_request_pdu_t *dlsch = &dl_config_req_body->dl_config_pdu_list[i]; + if (dlsch->pdu_type != NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) { LOG_E(MAC, "expected DLSCH PDU at index %d\n", i); continue; } + dl_config_req_UE_MAC_dci(NFAPI_SFNSF2SFN(dl_config_req->sfn_sf), NFAPI_SFNSF2SF(dl_config_req->sfn_sf), pdu, @@ -1125,8 +1111,10 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) } } } + if (hi_dci0_req) { nfapi_hi_dci0_request_body_t *hi_dci0_body = &hi_dci0_req->hi_dci0_request_body; + for (int i = 0; i < hi_dci0_body->number_of_dci + hi_dci0_body->number_of_hi; i++) { nfapi_hi_dci0_request_pdu_t *pdu = &hi_dci0_body->hi_dci0_pdu_list[i]; hi_dci0_req_UE_MAC(NFAPI_SFNSF2SFN(hi_dci0_req->sfn_sf), @@ -1139,13 +1127,13 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) for (ue_index = 0; ue_index < ue_num; ue_index++) { ue_Mod_id = ue_thread_id + NB_THREAD_INST * ue_index; // Always 0 in standalone pnf mode UE = PHY_vars_UE_g[ue_Mod_id][0]; - #if UE_TIMING_TRACE start_meas(&UE->generic_stat); #endif int rx_frame = NFAPI_SFNSF2SF(sfn_sf) < 4 ? (NFAPI_SFNSF2SFN(sfn_sf) + 1023) % 1024 : NFAPI_SFNSF2SFN(sfn_sf); // subtracting 4 from subframe_tx int rx_subframe = NFAPI_SFNSF2SF(sfn_sf) < 4 ? NFAPI_SFNSF2SF(sfn_sf) + 6 : NFAPI_SFNSF2SF(sfn_sf) - 4; LOG_D(MAC, "rx_frame %d rx_subframe %d\n", rx_frame, rx_subframe); + if (UE->mac_enabled == 1) { ret = ue_scheduler(ue_Mod_id, rx_frame, @@ -1168,178 +1156,171 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) // Prepare the future Tx data if ((subframe_select(&UE->frame_parms, NFAPI_SFNSF2SF(sfn_sf)) == SF_UL) || - (UE->frame_parms.frame_type == FDD)) - { - if (UE->mode != loop_through_memory) - { - // We make the start of RA between consecutive UEs differ by 20 frames - //if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id == 0) || (UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id>0 && rx_frame >= UE_mac_inst[Mod_id-1].ra_frame + 20) ) { - if (UE_mac_inst[ue_Mod_id].UE_mode[0] == RA_RESPONSE && - is_prach_subframe(&UE->frame_parms, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf))) - { - UE_mac_inst[ue_Mod_id].UE_mode[0] = PRACH; - } - LOG_D(MAC, "UE_mode: %d\n", UE_mac_inst[ue_Mod_id].UE_mode[0]); - if (UE_mac_inst[ue_Mod_id].UE_mode[0] == PRACH) - { //&& ue_Mod_id == next_Mod_id) { - next_ra_frame++; - if (next_ra_frame > 500) - { - // check if we have PRACH opportunity - if (is_prach_subframe(&UE->frame_parms, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)) && UE_mac_inst[ue_Mod_id].SI_Decoded == 1) - { - // The one working strangely... - //if (is_prach_subframe(&UE->frame_parms,NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf) && Mod_id == (module_id_t) init_ra_UE) ) { - PRACH_RESOURCES_t *prach_resources = ue_get_rach(ue_Mod_id, 0, NFAPI_SFNSF2SFN(sfn_sf), 0, NFAPI_SFNSF2SF(sfn_sf)); - if (prach_resources != NULL) - { - LOG_I(MAC, "preamble_received_tar_power: %d\n", - prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER); - UE_mac_inst[ue_Mod_id].ra_frame = NFAPI_SFNSF2SFN(sfn_sf); - LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d frame %d subframe %d\n", ue_Mod_id, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); - fill_rach_indication_UE_MAC(ue_Mod_id, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf), UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); - sent_any = true; - Msg1_transmitted(ue_Mod_id, 0, NFAPI_SFNSF2SFN(sfn_sf), 0); - UE_mac_inst[ue_Mod_id].UE_mode[0] = RA_RESPONSE; - next_Mod_id = ue_Mod_id + 1; - //next_ra_frame = (rx_frame + 20)%1000; - next_ra_frame = 0; - } - //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); + (UE->frame_parms.frame_type == FDD)) { + // We make the start of RA between consecutive UEs differ by 20 frames + //if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id == 0) || (UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id>0 && rx_frame >= UE_mac_inst[Mod_id-1].ra_frame + 20) ) { + if (UE_mac_inst[ue_Mod_id].UE_mode[0] == RA_RESPONSE && + is_prach_subframe(&UE->frame_parms, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf))) { + UE_mac_inst[ue_Mod_id].UE_mode[0] = PRACH; + } + + LOG_D(MAC, "UE_mode: %d\n", UE_mac_inst[ue_Mod_id].UE_mode[0]); + + if (UE_mac_inst[ue_Mod_id].UE_mode[0] == PRACH) { + //&& ue_Mod_id == next_Mod_id) { + next_ra_frame++; + + if (next_ra_frame > 500) { + // check if we have PRACH opportunity + if (is_prach_subframe(&UE->frame_parms, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)) && UE_mac_inst[ue_Mod_id].SI_Decoded == 1) { + // The one working strangely... + //if (is_prach_subframe(&UE->frame_parms,NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf) && Mod_id == (module_id_t) init_ra_UE) ) { + PRACH_RESOURCES_t *prach_resources = ue_get_rach(ue_Mod_id, 0, NFAPI_SFNSF2SFN(sfn_sf), 0, NFAPI_SFNSF2SF(sfn_sf)); + + if (prach_resources != NULL) { + LOG_I(MAC, "preamble_received_tar_power: %d\n", + prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER); + UE_mac_inst[ue_Mod_id].ra_frame = NFAPI_SFNSF2SFN(sfn_sf); + LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d frame %d subframe %d\n", ue_Mod_id, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); + fill_rach_indication_UE_MAC(ue_Mod_id, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf), UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); + sent_any = true; + Msg1_transmitted(ue_Mod_id, 0, NFAPI_SFNSF2SFN(sfn_sf), 0); + UE_mac_inst[ue_Mod_id].UE_mode[0] = RA_RESPONSE; + next_Mod_id = ue_Mod_id + 1; + //next_ra_frame = (rx_frame + 20)%1000; + next_ra_frame = 0; } + + //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); } - } // mode is PRACH - - // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger - // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). - // Generate UL_indications which correspond to UL traffic. - if (ul_config_req != NULL) - { //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){ - ul_config_req_UE_MAC(ul_config_req, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf), ue_Mod_id); } - } + } // mode is PRACH - phy_procedures_UE_SL_RX(UE, proc); - } - else - { - LOG_I(MAC, "Skipping subframe select statement proxy SFN.SF: %d.%d\n", - NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); - if (ul_config_req != NULL) - { - LOG_I(MAC, "Skipping subframe select statement ul_config_req SFN.SF: %d.%d\n", - NFAPI_SFNSF2SFN(ul_config_req->sfn_sf), NFAPI_SFNSF2SF(ul_config_req->sfn_sf)); + // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger + // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). + // Generate UL_indications which correspond to UL traffic. + if (ul_config_req != NULL) { + //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){ + ul_config_req_UE_MAC(ul_config_req, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf), ue_Mod_id); } } - } //for (Mod_id=0; Mod_idcrc_ind.crc_indication_body.number_of_crcs > 0) { - //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf)); - //LOG_I(MAC, "ul_config_req_UE_MAC 2.2, SFN/SF of PNF counter:%d.%d, number_of_crcs: %d \n", timer_frame, timer_subframe, UL_INFO->crc_ind.crc_indication_body.number_of_crcs); - send_standalone_msg(UL_INFO, UL_INFO->crc_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.21 \n"); - UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; - } + phy_procedures_UE_SL_RX(UE, proc); + } else { + LOG_I(MAC, "Skipping subframe select statement proxy SFN.SF: %d.%d\n", + NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); - if (UL_INFO->rx_ind.rx_indication_body.number_of_pdus > 0) { - - //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf)); - //LOG_I(MAC, "ul_config_req_UE_MAC 2.3, SFN/SF of PNF counter:%d.%d, number_of_pdus: %d \n", timer_frame, timer_subframe, UL_INFO->rx_ind.rx_indication_body.number_of_pdus); - send_standalone_msg(UL_INFO, UL_INFO->rx_ind.header.message_id); - sent_any = true; - - //LOG_I(MAC, "ul_config_req_UE_MAC 2.31 \n"); - UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; - } - - if (UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis > 0) { - send_standalone_msg(UL_INFO, UL_INFO->cqi_ind.header.message_id); - sent_any = true; - UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; - } - - if (UL_INFO->harq_ind.harq_indication_body.number_of_harqs > 0) { - //LOG_D(MAC, "ul_config_req_UE_MAC 2.4, SFN/SF of PNF counter:%d.%d, number_of_harqs: %d \n", timer_frame, timer_subframe, UL_INFO->harq_ind.harq_indication_body.number_of_harqs); - send_standalone_msg(UL_INFO, UL_INFO->harq_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.41 \n"); - UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; - } - - if (UL_INFO->sr_ind.sr_indication_body.number_of_srs > 0) { - //LOG_I(MAC, "ul_config_req_UE_MAC 2.5, SFN/SF of PNF counter:%d.%d, number_of_srs: %d \n", timer_frame, timer_subframe, UL_INFO->sr_ind.sr_indication_body.number_of_srs); - send_standalone_msg(UL_INFO, UL_INFO->sr_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.51 \n"); - UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; - } - - // De-allocate memory of nfapi requests copies before next subframe round - if (dl_config_req_tx_req != NULL) { - if (dl_config_req_tx_req->dl_config_req->vendor_extension != NULL) { - free(dl_config_req_tx_req->dl_config_req->vendor_extension); - dl_config_req_tx_req->dl_config_req->vendor_extension = NULL; + if (ul_config_req != NULL) { + LOG_I(MAC, "Skipping subframe select statement ul_config_req SFN.SF: %d.%d\n", + NFAPI_SFNSF2SFN(ul_config_req->sfn_sf), NFAPI_SFNSF2SF(ul_config_req->sfn_sf)); } - - if (dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list != NULL) { - free(dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list); - dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list = NULL; - } - nfapi_free_tx_req_pdu_list(dl_config_req_tx_req->tx_req_pdu_list); - dl_config_req_tx_req->tx_req_pdu_list = NULL; - - free(dl_config_req_tx_req->dl_config_req); - dl_config_req_tx_req->dl_config_req = NULL; - - free(dl_config_req_tx_req); - dl_config_req_tx_req = NULL; } + } //for (Mod_id=0; Mod_idul_config_request_body.ul_config_pdu_list != NULL) { - free(ul_config_req->ul_config_request_body.ul_config_pdu_list); - ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; - } - - free(ul_config_req); - ul_config_req = NULL; - } - - if (hi_dci0_req != NULL) { - if (hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list != NULL) { - free(hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list); - hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = NULL; - } - - free(hi_dci0_req); - hi_dci0_req = NULL; - } - if (!sent_any) - { - send_standalone_dummy(); - } + if (UL_INFO->crc_ind.crc_indication_body.number_of_crcs > 0) { + //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf)); + //LOG_I(MAC, "ul_config_req_UE_MAC 2.2, SFN/SF of PNF counter:%d.%d, number_of_crcs: %d \n", timer_frame, timer_subframe, UL_INFO->crc_ind.crc_indication_body.number_of_crcs); + send_standalone_msg(UL_INFO, UL_INFO->crc_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.21 \n"); + UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; } - // Free UL_INFO messages - free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); - UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; - free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); - UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; - free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); - UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; - free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); - UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; - free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); - UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; - free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); - UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; - free(UL_INFO); - UL_INFO = NULL; + if (UL_INFO->rx_ind.rx_indication_body.number_of_pdus > 0) { + //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf)); + //LOG_I(MAC, "ul_config_req_UE_MAC 2.3, SFN/SF of PNF counter:%d.%d, number_of_pdus: %d \n", timer_frame, timer_subframe, UL_INFO->rx_ind.rx_indication_body.number_of_pdus); + send_standalone_msg(UL_INFO, UL_INFO->rx_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.31 \n"); + UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; + } - // thread finished - free(arg); - return NULL; + if (UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis > 0) { + send_standalone_msg(UL_INFO, UL_INFO->cqi_ind.header.message_id); + sent_any = true; + UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; + } + + if (UL_INFO->harq_ind.harq_indication_body.number_of_harqs > 0) { + //LOG_D(MAC, "ul_config_req_UE_MAC 2.4, SFN/SF of PNF counter:%d.%d, number_of_harqs: %d \n", timer_frame, timer_subframe, UL_INFO->harq_ind.harq_indication_body.number_of_harqs); + send_standalone_msg(UL_INFO, UL_INFO->harq_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.41 \n"); + UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; + } + + if (UL_INFO->sr_ind.sr_indication_body.number_of_srs > 0) { + //LOG_I(MAC, "ul_config_req_UE_MAC 2.5, SFN/SF of PNF counter:%d.%d, number_of_srs: %d \n", timer_frame, timer_subframe, UL_INFO->sr_ind.sr_indication_body.number_of_srs); + send_standalone_msg(UL_INFO, UL_INFO->sr_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.51 \n"); + UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; + } + + // De-allocate memory of nfapi requests copies before next subframe round + if (dl_config_req_tx_req != NULL) { + if (dl_config_req_tx_req->dl_config_req->vendor_extension != NULL) { + free(dl_config_req_tx_req->dl_config_req->vendor_extension); + dl_config_req_tx_req->dl_config_req->vendor_extension = NULL; + } + + if (dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list != NULL) { + free(dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list); + dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list = NULL; + } + + nfapi_free_tx_req_pdu_list(dl_config_req_tx_req->tx_req_pdu_list); + dl_config_req_tx_req->tx_req_pdu_list = NULL; + free(dl_config_req_tx_req->dl_config_req); + dl_config_req_tx_req->dl_config_req = NULL; + free(dl_config_req_tx_req); + dl_config_req_tx_req = NULL; + } + + if (ul_config_req != NULL) { + if (ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { + free(ul_config_req->ul_config_request_body.ul_config_pdu_list); + ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; + } + + free(ul_config_req); + ul_config_req = NULL; + } + + if (hi_dci0_req != NULL) { + if (hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list != NULL) { + free(hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list); + hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = NULL; + } + + free(hi_dci0_req); + hi_dci0_req = NULL; + } + + if (!sent_any) { + send_standalone_dummy(); + } +} + +// Free UL_INFO messages +free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); +UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; +free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); +UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; +free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); +UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; +free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); +UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; +free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); +UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; +free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); +UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; +free(UL_INFO); +UL_INFO = NULL; + +// thread finished +free(arg); +return NULL; } /*! @@ -1350,8 +1331,7 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) -{ +static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) { #if 0 // TODO: doesn't currently compile, obviated by multi-ue proxy thread_top_init("UE_phy_stub_thread_rxn_txnp4",1,870000L,1000000L,1000000L); // for multipule UE's L2-emulator @@ -1377,7 +1357,6 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) proc = &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0]; phy_stub_ticking->num_single_thread[ue_thread_id] = -1; UE = rtd->UE; - UL_INFO = (UL_IND_t *)malloc(sizeof(UL_IND_t)); UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_rx_indication_pdu_t)); UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; @@ -1489,19 +1468,23 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) } if (dl_config_req && tx_req_pdu_list) { - nfapi_dl_config_request_body_t* dl_config_req_body = &dl_config_req->dl_config_request_body; + nfapi_dl_config_request_body_t *dl_config_req_body = &dl_config_req->dl_config_request_body; + for (int i = 0; i < dl_config_req_body->number_pdu; ++i) { - nfapi_dl_config_request_pdu_t* pdu = &dl_config_req_body->dl_config_pdu_list[i]; + nfapi_dl_config_request_pdu_t *pdu = &dl_config_req_body->dl_config_pdu_list[i]; + if (pdu->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) { i += 1; AssertFatal(i < dl_config_req->dl_config_request_body.number_pdu, "Need PDU following DCI at index %d, but not found\n", i); nfapi_dl_config_request_pdu_t *dlsch = &dl_config_req_body->dl_config_pdu_list[i]; + if (dlsch->pdu_type != NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) { LOG_E(MAC, "expected DLSCH PDU at index %d\n", i); continue; } + dl_config_req_UE_MAC_dci(NFAPI_SFNSF2SFN(dl_config_req->sfn_sf), NFAPI_SFNSF2SF(dl_config_req->sfn_sf), pdu, @@ -1523,8 +1506,9 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) if (hi_dci0_req) { nfapi_hi_dci0_request_body_t *hi_dci0_body = &hi_dci0_req->hi_dci0_request_body; + for (int i = 0; i < hi_dci0_body->number_of_dci + hi_dci0_body->number_of_hi; i++) { - nfapi_hi_dci0_request_pdu_t* pdu = &hi_dci0_body->hi_dci0_pdu_list[i]; + nfapi_hi_dci0_request_pdu_t *pdu = &hi_dci0_body->hi_dci0_pdu_list[i]; hi_dci0_req_UE_MAC(NFAPI_SFNSF2SFN(hi_dci0_req->sfn_sf), NFAPI_SFNSF2SF(hi_dci0_req->sfn_sf), pdu, @@ -1592,44 +1576,41 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || (UE->frame_parms.frame_type == FDD) ) - if (UE->mode != loop_through_memory) { - // We make the start of RA between consecutive UEs differ by 20 frames - //if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id == 0) || (UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id>0 && proc->frame_rx >= UE_mac_inst[Mod_id-1].ra_frame + 20) ) { - if (UE_mac_inst[ue_Mod_id].UE_mode[0] == PRACH && ue_Mod_id == next_Mod_id) { - next_ra_frame++; - if(next_ra_frame > 500) { - // check if we have PRACH opportunity - if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx) && UE_mac_inst[ue_Mod_id].SI_Decoded == 1) { - // The one working strangely... - //if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx && Mod_id == (module_id_t) init_ra_UE) ) { - PRACH_RESOURCES_t *prach_resources = ue_get_rach(ue_Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx); + // We make the start of RA between consecutive UEs differ by 20 frames + //if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id == 0) || (UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id>0 && proc->frame_rx >= UE_mac_inst[Mod_id-1].ra_frame + 20) ) { + if (UE_mac_inst[ue_Mod_id].UE_mode[0] == PRACH && ue_Mod_id == next_Mod_id) { + next_ra_frame++; - if(prach_resources!=NULL ) { - UE_mac_inst[ue_Mod_id].ra_frame = proc->frame_rx; - LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d frame %d subframe %d\n", ue_Mod_id,proc->frame_tx, proc->subframe_tx); - fill_rach_indication_UE_MAC(ue_Mod_id, proc->frame_tx,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); - Msg1_transmitted(ue_Mod_id, 0, proc->frame_tx, 0); - UE_mac_inst[ue_Mod_id].UE_mode[0] = RA_RESPONSE; - next_Mod_id = ue_Mod_id + 1; - //next_ra_frame = (proc->frame_rx + 20)%1000; - next_ra_frame = 0; - } + if(next_ra_frame > 500) { + // check if we have PRACH opportunity + if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx) && UE_mac_inst[ue_Mod_id].SI_Decoded == 1) { + // The one working strangely... + //if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx && Mod_id == (module_id_t) init_ra_UE) ) { + PRACH_RESOURCES_t *prach_resources = ue_get_rach(ue_Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx); - //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); + if(prach_resources!=NULL ) { + UE_mac_inst[ue_Mod_id].ra_frame = proc->frame_rx; + LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d frame %d subframe %d\n", ue_Mod_id,proc->frame_tx, proc->subframe_tx); + fill_rach_indication_UE_MAC(ue_Mod_id, proc->frame_tx,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); + Msg1_transmitted(ue_Mod_id, 0, proc->frame_tx, 0); + UE_mac_inst[ue_Mod_id].UE_mode[0] = RA_RESPONSE; + next_Mod_id = ue_Mod_id + 1; + //next_ra_frame = (proc->frame_rx + 20)%1000; + next_ra_frame = 0; } + + //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); } - } // mode is PRACH - - // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger - // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). - // Generate UL_indications which correspond to UL traffic. - if(ul_config_req!=NULL) { //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){ - ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, ue_Mod_id); } - } + } // mode is PRACH - phy_procedures_UE_SL_RX(UE,proc); + // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger + // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). + // Generate UL_indications which correspond to UL traffic. + if(ul_config_req!=NULL) { //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){ + ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, ue_Mod_id); + } } //for (Mod_id=0; Mod_idnum_single_thread[ue_thread_id] = -1; @@ -1709,6 +1690,7 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) tx_req_pdu_list[i].segments[j].segment_data = NULL; } } + tx_req_num_elems = 0; free(tx_req_pdu_list); tx_req_pdu_list = NULL; @@ -1752,7 +1734,6 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) free(UL_INFO); UL_INFO = NULL; #endif // disabled UE_phy_stub_single_thread_rxn_txnp4 - // thread finished free(arg); return NULL; @@ -1767,9 +1748,8 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -static void *UE_phy_stub_thread_rxn_txnp4(void *arg) -{ - #if 0 +static void *UE_phy_stub_thread_rxn_txnp4(void *arg) { +#if 0 thread_top_init("UE_phy_stub_thread_rxn_txnp4",1,870000L,1000000L,1000000L); module_id_t Mod_id = 0; static __thread int UE_thread_rxtx_retval; @@ -1880,45 +1860,42 @@ static void *UE_phy_stub_thread_rxn_txnp4(void *arg) if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || (UE->frame_parms.frame_type == FDD) ) - if (UE->mode != loop_through_memory) { - if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH) ) { - // check if we have PRACH opportunity - if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx)) { - PRACH_RESOURCES_t *prach_resources = ue_get_rach(Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx); + if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH) ) { + // check if we have PRACH opportunity + if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx)) { + PRACH_RESOURCES_t *prach_resources = ue_get_rach(Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx); - if(prach_resources!=NULL) { - fill_rach_indication_UE_MAC(Mod_id, proc->frame_tx,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); - Msg1_transmitted(Mod_id, 0, proc->frame_tx, 0); - UE_mac_inst[Mod_id].UE_mode[0] = RA_RESPONSE; - } - - //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); - } - } // mode is PRACH - - // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger - // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). - // Generate UL_indications which correspond to UL traffic. - if(ul_config_req!= NULL && ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { - //LOG_I(MAC, "UE_phy_stub_thread_rxn_txnp4 ul_config_req is not NULL \n"); - ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, Mod_id); - - if(ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { - free(ul_config_req->ul_config_request_body.ul_config_pdu_list); - ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; + if(prach_resources!=NULL) { + fill_rach_indication_UE_MAC(Mod_id, proc->frame_tx,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI); + Msg1_transmitted(Mod_id, 0, proc->frame_tx, 0); + UE_mac_inst[Mod_id].UE_mode[0] = RA_RESPONSE; } - free(ul_config_req); - ul_config_req = NULL; - } else if(ul_config_req!=NULL) { - free(ul_config_req); - ul_config_req = NULL; + //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode); } + } // mode is PRACH + + // Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger + // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB). + // Generate UL_indications which correspond to UL traffic. + if(ul_config_req!= NULL && ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { + //LOG_I(MAC, "UE_phy_stub_thread_rxn_txnp4 ul_config_req is not NULL \n"); + ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, Mod_id); + + if(ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { + free(ul_config_req->ul_config_request_body.ul_config_pdu_list); + ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; } - phy_procedures_UE_SL_RX(UE,proc); + free(ul_config_req); + ul_config_req = NULL; + } else if(ul_config_req!=NULL) { + free(ul_config_req); + ul_config_req = NULL; + } } - #endif // disabled + +#endif // disabled // thread finished free(arg); return NULL; //return &UE_thread_rxtx_retval; @@ -1940,20 +1917,19 @@ void write_dummy(PHY_VARS_UE *UE, openair0_timestamp timestamp) { // struct complex16 v= {0}; void *samplesVoid[UE->frame_parms.nb_antennas_tx]; - + for ( int i=0; i < UE->frame_parms.nb_antennas_tx; i++) samplesVoid[i]=(void *)&v; - + AssertFatal( 1 == UE->rfdevice.trx_write_func(&UE->rfdevice, - timestamp+2*UE->frame_parms.samples_per_tti, - samplesVoid, - 1, - UE->frame_parms.nb_antennas_tx, - 1),""); + timestamp+2*UE->frame_parms.samples_per_tti, + samplesVoid, + 1, + UE->frame_parms.nb_antennas_tx, + 1),""); } -void *UE_thread(void *arg) -{ +void *UE_thread(void *arg) { PHY_VARS_UE *UE = (PHY_VARS_UE *) arg; // int tx_enabled = 0; int dummy_rx[UE->frame_parms.nb_antennas_rx][UE->frame_parms.samples_per_tti] __attribute__((aligned(32))); @@ -1966,10 +1942,11 @@ void *UE_thread(void *arg) int ret; cpu_set_t cpuset; CPU_ZERO(&cpuset); + if ( threads.main != -1 ) CPU_SET(threads.main, &cpuset); - init_thread(100000, 500000, FIFO_PRIORITY, &cpuset, "UHD Threads"); + init_thread(100000, 500000, FIFO_PRIORITY, &cpuset, "UHD Threads"); /* while (sync_var<0) pthread_cond_wait(&sync_cond, &sync_mutex); @@ -1996,46 +1973,45 @@ void *UE_thread(void *arg) int instance_cnt_synch = UE->proc.instance_cnt_synch; int is_synchronized = UE->is_synchronized; AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); - + if (is_synchronized == 0) { if (instance_cnt_synch < 0) { // we can invoke the synch - // we shift in time flow because the UE doesn't detect sync when frame alignment is not easy - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&dummy_rx[i][0]; - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti/2, - UE->frame_parms.nb_antennas_rx); - + // we shift in time flow because the UE doesn't detect sync when frame alignment is not easy + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&dummy_rx[i][0]; + + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti/2, + UE->frame_parms.nb_antennas_rx); + // grab 10 ms of signal and wakeup synch thread - - if (UE->mode != loop_through_memory) { - if (IS_SOFTMODEM_RFSIM ) { - for(int sf=0; sf<10; sf++) { - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.samples_per_tti*sf]; - - AssertFatal(UE->frame_parms.samples_per_tti == UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti, - UE->frame_parms.nb_antennas_rx), ""); - write_dummy(UE, timestamp); - } - } else { - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][0]; - - AssertFatal( UE->frame_parms.samples_per_tti*10 == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti*10, - UE->frame_parms.nb_antennas_rx), ""); - } - } + + if (IS_SOFTMODEM_RFSIM ) { + for(int sf=0; sf<10; sf++) { + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.samples_per_tti*sf]; + + AssertFatal(UE->frame_parms.samples_per_tti == UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti, + UE->frame_parms.nb_antennas_rx), ""); + write_dummy(UE, timestamp); + } + } else { + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][0]; + + AssertFatal( UE->frame_parms.samples_per_tti*10 == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti*10, + UE->frame_parms.nb_antennas_rx), ""); + } AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); instance_cnt_synch = ++UE->proc.instance_cnt_synch; @@ -2049,69 +2025,62 @@ void *UE_thread(void *arg) AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); } else { -#if OAISIM - (void)dummy_rx; /* avoid gcc warnings */ - usleep(500); -#else // grab 10 ms of signal into dummy buffer - if (UE->mode != loop_through_memory) { - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&dummy_rx[i][0]; + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&dummy_rx[i][0]; - for (int sf=0; sf<10; sf++) { - // printf("Reading dummy sf %d\n",sf); - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti, - UE->frame_parms.nb_antennas_rx); - if (IS_SOFTMODEM_RFSIM ) - write_dummy(UE, timestamp); - } - } -#endif + for (int sf=0; sf<10; sf++) { + // printf("Reading dummy sf %d\n",sf); + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti, + UE->frame_parms.nb_antennas_rx); + + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + } } } // UE->is_synchronized==0 else { if (start_rx_stream==0) { start_rx_stream=1; - if (UE->mode != loop_through_memory) { - if (UE->no_timing_correction==0) { - LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); - while ( UE->rx_offset ) { - size_t s=min(UE->rx_offset,UE->frame_parms.samples_per_tti); - AssertFatal(s == UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - (void **)UE->common_vars.rxdata, - s, - UE->frame_parms.nb_antennas_rx),""); - if (IS_SOFTMODEM_RFSIM ) - write_dummy(UE, timestamp); - UE->rx_offset-=s; - } + if (UE->no_timing_correction==0) { + LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); + + while ( UE->rx_offset ) { + size_t s=min(UE->rx_offset,UE->frame_parms.samples_per_tti); + AssertFatal(s == UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void **)UE->common_vars.rxdata, + s, + UE->frame_parms.nb_antennas_rx),""); + + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + + UE->rx_offset-=s; } + } - UE->rx_offset=0; - UE->time_sync_cell=0; + UE->rx_offset=0; + UE->time_sync_cell=0; - //UE->proc.proc_rxtx[0].frame_rx++; - //UE->proc.proc_rxtx[1].frame_rx++; - for (th_id=0; th_id < RX_NB_TH; th_id++) { - UE->proc.proc_rxtx[th_id].frame_rx++; - } + //UE->proc.proc_rxtx[0].frame_rx++; + //UE->proc.proc_rxtx[1].frame_rx++; + for (th_id=0; th_id < RX_NB_TH; th_id++) { + UE->proc.proc_rxtx[th_id].frame_rx++; + } - // read in first symbol - AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - (void **)UE->common_vars.rxdata, - UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, - UE->frame_parms.nb_antennas_rx),""); - slot_fep(UE,0, 0, 0, 0, 0); - } //UE->mode != loop_through_memory - else - rt_sleep_ns(1000*1000); + // read in first symbol + AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void **)UE->common_vars.rxdata, + UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, + UE->frame_parms.nb_antennas_rx),""); + slot_fep(UE,0, 0, 0, 0, 0); } else { sub_frame++; sub_frame%=10; @@ -2130,7 +2099,8 @@ void *UE_thread(void *arg) pthread_mutex_unlock(&proc->mutex_rxtx); } - usleep(300); + + usleep(300); } LOG_D(PHY,"Process Subframe %d thread Idx %d \n", sub_frame, UE->current_thread_id[sub_frame]); @@ -2139,130 +2109,129 @@ void *UE_thread(void *arg) if(thread_idx>=RX_NB_TH) thread_idx = 0; - if (UE->mode != loop_through_memory) { - for (i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.ofdm_symbol_size+ - UE->frame_parms.nb_prefix_samples0+ - sub_frame*UE->frame_parms.samples_per_tti]; + for (i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.ofdm_symbol_size+ + UE->frame_parms.nb_prefix_samples0+ + sub_frame*UE->frame_parms.samples_per_tti]; - for (i=0; iframe_parms.nb_antennas_tx; i++) - txp[i] = (void *)&UE->common_vars.txdata[i][((sub_frame+2)%10)*UE->frame_parms.samples_per_tti]; + for (i=0; iframe_parms.nb_antennas_tx; i++) + txp[i] = (void *)&UE->common_vars.txdata[i][((sub_frame+2)%10)*UE->frame_parms.samples_per_tti]; - int readBlockSize, writeBlockSize; + int readBlockSize, writeBlockSize; - if (sub_frame<9) { - readBlockSize=UE->frame_parms.samples_per_tti; - writeBlockSize=UE->frame_parms.samples_per_tti; - } else { - // set TO compensation to zero - UE->rx_offset_diff = 0; - - // compute TO compensation that should be applied for this frame - - if (UE->no_timing_correction == 0) { - if ( UE->rx_offset < 5*UE->frame_parms.samples_per_tti && - UE->rx_offset > 0 ) - UE->rx_offset_diff = -1 ; - - if ( UE->rx_offset > 5*UE->frame_parms.samples_per_tti && - UE->rx_offset < 10*UE->frame_parms.samples_per_tti ) - UE->rx_offset_diff = 1; - } - - LOG_D(PHY,"AbsSubframe %d.%d SET rx_off_diff to %d rx_offset %d \n",proc->frame_rx,sub_frame,UE->rx_offset_diff,UE->rx_offset); - readBlockSize=UE->frame_parms.samples_per_tti - - UE->frame_parms.ofdm_symbol_size - - UE->frame_parms.nb_prefix_samples0 - - UE->rx_offset_diff; - writeBlockSize=UE->frame_parms.samples_per_tti - - UE->rx_offset_diff; - } - - AssertFatal(readBlockSize == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - readBlockSize, - UE->frame_parms.nb_antennas_rx),""); - AssertFatal( writeBlockSize == - UE->rfdevice.trx_write_func(&UE->rfdevice, - timestamp+ - (2*UE->frame_parms.samples_per_tti) - - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - - openair0_cfg[0].tx_sample_advance, - txp, - writeBlockSize, - UE->frame_parms.nb_antennas_tx, - 1),""); - - if( sub_frame==9) { - // read in first symbol of next frame and adjust for timing drift - int first_symbols=writeBlockSize-readBlockSize; - - if ( first_symbols > 0 ) - AssertFatal(first_symbols == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp1, - (void **)UE->common_vars.rxdata, - first_symbols, - UE->frame_parms.nb_antennas_rx),""); - - if ( first_symbols <0 ) - LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols); - } - - /* no timeout in IS_SOFTMODEM_RFSIM mode */ - if (IS_SOFTMODEM_RFSIM) { - ret = pthread_mutex_lock(&proc->mutex_rxtx); - } else { - struct timespec tv; - if (clock_gettime(CLOCK_REALTIME, &tv) != 0) { - perror("clock_gettime"); - exit(1); - } - tv.tv_nsec += 10*1000; - if (tv.tv_nsec >= 1000 * 1000 * 1000) { - tv.tv_sec++; - tv.tv_nsec -= 1000 * 1000 * 1000; - } - ret = pthread_mutex_timedlock(&proc->mutex_rxtx, &tv); - } - - // operate on thread sf mod 2 - if (ret != 0) { - if (ret == ETIMEDOUT) { - LOG_E(PHY,"Missed real time\n"); - continue; - } else { - LOG_E(PHY,"System error %s (%d)\n",strerror(errno),errno); - abort(); - } - } - - // usleep(3000); - if(sub_frame == 0) { - //UE->proc.proc_rxtx[0].frame_rx++; - //UE->proc.proc_rxtx[1].frame_rx++; - for (th_id=0; th_id < RX_NB_TH; th_id++) { - UE->proc.proc_rxtx[th_id].frame_rx++; - } - } - - proc->subframe_rx=sub_frame; - proc->subframe_tx=(sub_frame+4)%10; - proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0); - proc->timestamp_tx = timestamp+ - (4*UE->frame_parms.samples_per_tti)- - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; - proc->instance_cnt_rxtx++; - LOG_D( PHY, "[SCHED][UE %d] UE RX instance_cnt_rxtx %d subframe %d !!\n", UE->Mod_id, proc->instance_cnt_rxtx,proc->subframe_rx); - T(T_UE_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx%1024), T_INT(proc->subframe_rx)); - AssertFatal (pthread_cond_signal(&proc->cond_rxtx) ==0,""); - AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,""); + if (sub_frame<9) { + readBlockSize=UE->frame_parms.samples_per_tti; + writeBlockSize=UE->frame_parms.samples_per_tti; } else { - printf("Processing subframe %d",proc->subframe_rx); - getchar(); + // set TO compensation to zero + UE->rx_offset_diff = 0; + + // compute TO compensation that should be applied for this frame + + if (UE->no_timing_correction == 0) { + if ( UE->rx_offset < 5*UE->frame_parms.samples_per_tti && + UE->rx_offset > 0 ) + UE->rx_offset_diff = -1 ; + + if ( UE->rx_offset > 5*UE->frame_parms.samples_per_tti && + UE->rx_offset < 10*UE->frame_parms.samples_per_tti ) + UE->rx_offset_diff = 1; + } + + LOG_D(PHY,"AbsSubframe %d.%d SET rx_off_diff to %d rx_offset %d \n",proc->frame_rx,sub_frame,UE->rx_offset_diff,UE->rx_offset); + readBlockSize=UE->frame_parms.samples_per_tti - + UE->frame_parms.ofdm_symbol_size - + UE->frame_parms.nb_prefix_samples0 - + UE->rx_offset_diff; + writeBlockSize=UE->frame_parms.samples_per_tti - + UE->rx_offset_diff; } + + AssertFatal(readBlockSize == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + readBlockSize, + UE->frame_parms.nb_antennas_rx),""); + AssertFatal( writeBlockSize == + UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+ + (2*UE->frame_parms.samples_per_tti) - + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - + openair0_cfg[0].tx_sample_advance, + txp, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + 1),""); + + if( sub_frame==9) { + // read in first symbol of next frame and adjust for timing drift + int first_symbols=writeBlockSize-readBlockSize; + + if ( first_symbols > 0 ) + AssertFatal(first_symbols == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp1, + (void **)UE->common_vars.rxdata, + first_symbols, + UE->frame_parms.nb_antennas_rx),""); + + if ( first_symbols <0 ) + LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols); + } + + /* no timeout in IS_SOFTMODEM_RFSIM mode */ + if (IS_SOFTMODEM_RFSIM) { + ret = pthread_mutex_lock(&proc->mutex_rxtx); + } else { + struct timespec tv; + + if (clock_gettime(CLOCK_REALTIME, &tv) != 0) { + perror("clock_gettime"); + exit(1); + } + + tv.tv_nsec += 10*1000; + + if (tv.tv_nsec >= 1000 * 1000 * 1000) { + tv.tv_sec++; + tv.tv_nsec -= 1000 * 1000 * 1000; + } + + ret = pthread_mutex_timedlock(&proc->mutex_rxtx, &tv); + } + + // operate on thread sf mod 2 + if (ret != 0) { + if (ret == ETIMEDOUT) { + LOG_E(PHY,"Missed real time\n"); + continue; + } else { + LOG_E(PHY,"System error %s (%d)\n",strerror(errno),errno); + abort(); + } + } + + // usleep(3000); + if(sub_frame == 0) { + //UE->proc.proc_rxtx[0].frame_rx++; + //UE->proc.proc_rxtx[1].frame_rx++; + for (th_id=0; th_id < RX_NB_TH; th_id++) { + UE->proc.proc_rxtx[th_id].frame_rx++; + } + } + + proc->subframe_rx=sub_frame; + proc->subframe_tx=(sub_frame+4)%10; + proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0); + proc->timestamp_tx = timestamp+ + (4*UE->frame_parms.samples_per_tti)- + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; + proc->instance_cnt_rxtx++; + LOG_D( PHY, "[SCHED][UE %d] UE RX instance_cnt_rxtx %d subframe %d !!\n", UE->Mod_id, proc->instance_cnt_rxtx,proc->subframe_rx); + T(T_UE_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx%1024), T_INT(proc->subframe_rx)); + AssertFatal (pthread_cond_signal(&proc->cond_rxtx) ==0,""); + AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,""); } // start_rx_stream==1 } // UE->is_synchronized==1 } // while !oai_exit @@ -2283,8 +2252,7 @@ void *UE_thread(void *arg) * - UE_thread_dlsch_proc_slot1 * and the locking between them. */ -void init_UE_threads(int inst) -{ +void init_UE_threads(int inst) { struct rx_tx_thread_data *rtd; PHY_VARS_UE *UE; AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is NULL\n"); @@ -2339,8 +2307,7 @@ void init_UE_threads(int inst) * - UE_thread_dlsch_proc_slot1 * and the locking between them. */ -void init_UE_single_thread_stub(int nb_inst) -{ +void init_UE_single_thread_stub(int nb_inst) { struct rx_tx_thread_data *rtd; PHY_VARS_UE *UE; @@ -2368,8 +2335,8 @@ void init_UE_single_thread_stub(int nb_inst) // In phy_stub_UE mode due to less heavy processing operations we don't need two threads //int nb_threads=RX_NB_TH; int nb_threads=1; + void *(*task_func)(void *); - void* (*task_func)(void*); if (NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) { task_func = UE_phy_stub_standalone_pnf_task; } else { @@ -2413,8 +2380,7 @@ void init_UE_single_thread_stub(int nb_inst) * - UE_thread_dlsch_proc_slot1 * and the locking between them. */ -void init_UE_threads_stub(int inst) -{ +void init_UE_threads_stub(int inst) { struct rx_tx_thread_data *rtd; PHY_VARS_UE *UE; AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is NULL\n"); @@ -2451,8 +2417,7 @@ void init_UE_threads_stub(int inst) } -void fill_ue_band_info(void) -{ +void fill_ue_band_info(void) { LTE_UE_EUTRA_Capability_t *UE_EUTRA_Capability = UE_rrc_inst[0].UECap->UE_EUTRA_Capability; int i,j; bands_to_scan.nbands = UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; @@ -2477,8 +2442,7 @@ void fill_ue_band_info(void) } int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, - openair0_config_t *openair0_cfg) -{ + openair0_config_t *openair0_cfg) { int i, CC_id; LTE_DL_FRAME_PARMS *frame_parms; @@ -2520,8 +2484,7 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, // playing the role of nfapi-pnf. //02/02/2018 -static void *timer_thread( void *param ) -{ +static void *timer_thread( void *param ) { thread_top_init("timer_thread",1,870000L,1000000L,1000000L); timer_subframe =9; timer_frame =1023; @@ -2647,8 +2610,7 @@ static void *timer_thread( void *param ) } -int init_timer_thread(void) -{ +int init_timer_thread(void) { //PHY_VARS_UE *UE=PHY_vars_UE_g[0]; PHY_VARS_UE *UE=PHY_vars_UE_g[0][0]; phy_stub_ticking = (SF_ticking *)malloc(sizeof(SF_ticking)); @@ -2670,8 +2632,7 @@ int init_timer_thread(void) */ int8_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB, - find_type_t type) -{ + find_type_t type) { printf("you cannot read this\n"); abort(); } From 421603534c7db096fd7b4c21da302bfb28b712a2 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 11 Apr 2022 10:52:53 +0200 Subject: [PATCH 075/226] fix regression --- targets/RT/USER/lte-ue.c | 204 +++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 104 deletions(-) diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 8565e36e87..2b3a680713 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1203,124 +1203,120 @@ static void *UE_phy_stub_standalone_pnf_task(void *arg) { //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){ ul_config_req_UE_MAC(ul_config_req, NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf), ue_Mod_id); } + } else { + LOG_I(MAC, "Skipping subframe select statement proxy SFN.SF: %d.%d\n", + NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); + + if (ul_config_req != NULL) { + LOG_I(MAC, "Skipping subframe select statement ul_config_req SFN.SF: %d.%d\n", + NFAPI_SFNSF2SFN(ul_config_req->sfn_sf), NFAPI_SFNSF2SF(ul_config_req->sfn_sf)); + } + } + } //for (Mod_id=0; Mod_idcrc_ind.crc_indication_body.number_of_crcs > 0) { + //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf)); + //LOG_I(MAC, "ul_config_req_UE_MAC 2.2, SFN/SF of PNF counter:%d.%d, number_of_crcs: %d \n", timer_frame, timer_subframe, UL_INFO->crc_ind.crc_indication_body.number_of_crcs); + send_standalone_msg(UL_INFO, UL_INFO->crc_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.21 \n"); + UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; + } + + if (UL_INFO->rx_ind.rx_indication_body.number_of_pdus > 0) { + //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf)); + //LOG_I(MAC, "ul_config_req_UE_MAC 2.3, SFN/SF of PNF counter:%d.%d, number_of_pdus: %d \n", timer_frame, timer_subframe, UL_INFO->rx_ind.rx_indication_body.number_of_pdus); + send_standalone_msg(UL_INFO, UL_INFO->rx_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.31 \n"); + UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; + } + + if (UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis > 0) { + send_standalone_msg(UL_INFO, UL_INFO->cqi_ind.header.message_id); + sent_any = true; + UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; + } + + if (UL_INFO->harq_ind.harq_indication_body.number_of_harqs > 0) { + //LOG_D(MAC, "ul_config_req_UE_MAC 2.4, SFN/SF of PNF counter:%d.%d, number_of_harqs: %d \n", timer_frame, timer_subframe, UL_INFO->harq_ind.harq_indication_body.number_of_harqs); + send_standalone_msg(UL_INFO, UL_INFO->harq_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.41 \n"); + UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; + } + + if (UL_INFO->sr_ind.sr_indication_body.number_of_srs > 0) { + //LOG_I(MAC, "ul_config_req_UE_MAC 2.5, SFN/SF of PNF counter:%d.%d, number_of_srs: %d \n", timer_frame, timer_subframe, UL_INFO->sr_ind.sr_indication_body.number_of_srs); + send_standalone_msg(UL_INFO, UL_INFO->sr_ind.header.message_id); + sent_any = true; + //LOG_I(MAC, "ul_config_req_UE_MAC 2.51 \n"); + UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; + } + + // De-allocate memory of nfapi requests copies before next subframe round + if (dl_config_req_tx_req != NULL) { + if (dl_config_req_tx_req->dl_config_req->vendor_extension != NULL) { + free(dl_config_req_tx_req->dl_config_req->vendor_extension); + dl_config_req_tx_req->dl_config_req->vendor_extension = NULL; } - phy_procedures_UE_SL_RX(UE, proc); - } else { - LOG_I(MAC, "Skipping subframe select statement proxy SFN.SF: %d.%d\n", - NFAPI_SFNSF2SFN(sfn_sf), NFAPI_SFNSF2SF(sfn_sf)); - - if (ul_config_req != NULL) { - LOG_I(MAC, "Skipping subframe select statement ul_config_req SFN.SF: %d.%d\n", - NFAPI_SFNSF2SFN(ul_config_req->sfn_sf), NFAPI_SFNSF2SF(ul_config_req->sfn_sf)); + if (dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list != NULL) { + free(dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list); + dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list = NULL; } - } - } //for (Mod_id=0; Mod_idcrc_ind.crc_indication_body.number_of_crcs > 0) { - //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf)); - //LOG_I(MAC, "ul_config_req_UE_MAC 2.2, SFN/SF of PNF counter:%d.%d, number_of_crcs: %d \n", timer_frame, timer_subframe, UL_INFO->crc_ind.crc_indication_body.number_of_crcs); - send_standalone_msg(UL_INFO, UL_INFO->crc_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.21 \n"); - UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; - } - - if (UL_INFO->rx_ind.rx_indication_body.number_of_pdus > 0) { - //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf)); - //LOG_I(MAC, "ul_config_req_UE_MAC 2.3, SFN/SF of PNF counter:%d.%d, number_of_pdus: %d \n", timer_frame, timer_subframe, UL_INFO->rx_ind.rx_indication_body.number_of_pdus); - send_standalone_msg(UL_INFO, UL_INFO->rx_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.31 \n"); - UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; - } - - if (UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis > 0) { - send_standalone_msg(UL_INFO, UL_INFO->cqi_ind.header.message_id); - sent_any = true; - UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; - } - - if (UL_INFO->harq_ind.harq_indication_body.number_of_harqs > 0) { - //LOG_D(MAC, "ul_config_req_UE_MAC 2.4, SFN/SF of PNF counter:%d.%d, number_of_harqs: %d \n", timer_frame, timer_subframe, UL_INFO->harq_ind.harq_indication_body.number_of_harqs); - send_standalone_msg(UL_INFO, UL_INFO->harq_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.41 \n"); - UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; - } - - if (UL_INFO->sr_ind.sr_indication_body.number_of_srs > 0) { - //LOG_I(MAC, "ul_config_req_UE_MAC 2.5, SFN/SF of PNF counter:%d.%d, number_of_srs: %d \n", timer_frame, timer_subframe, UL_INFO->sr_ind.sr_indication_body.number_of_srs); - send_standalone_msg(UL_INFO, UL_INFO->sr_ind.header.message_id); - sent_any = true; - //LOG_I(MAC, "ul_config_req_UE_MAC 2.51 \n"); - UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; - } - - // De-allocate memory of nfapi requests copies before next subframe round - if (dl_config_req_tx_req != NULL) { - if (dl_config_req_tx_req->dl_config_req->vendor_extension != NULL) { - free(dl_config_req_tx_req->dl_config_req->vendor_extension); - dl_config_req_tx_req->dl_config_req->vendor_extension = NULL; + nfapi_free_tx_req_pdu_list(dl_config_req_tx_req->tx_req_pdu_list); + dl_config_req_tx_req->tx_req_pdu_list = NULL; + free(dl_config_req_tx_req->dl_config_req); + dl_config_req_tx_req->dl_config_req = NULL; + free(dl_config_req_tx_req); + dl_config_req_tx_req = NULL; } - if (dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list != NULL) { - free(dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list); - dl_config_req_tx_req->dl_config_req->dl_config_request_body.dl_config_pdu_list = NULL; + if (ul_config_req != NULL) { + if (ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { + free(ul_config_req->ul_config_request_body.ul_config_pdu_list); + ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; + } + + free(ul_config_req); + ul_config_req = NULL; } - nfapi_free_tx_req_pdu_list(dl_config_req_tx_req->tx_req_pdu_list); - dl_config_req_tx_req->tx_req_pdu_list = NULL; - free(dl_config_req_tx_req->dl_config_req); - dl_config_req_tx_req->dl_config_req = NULL; - free(dl_config_req_tx_req); - dl_config_req_tx_req = NULL; - } + if (hi_dci0_req != NULL) { + if (hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list != NULL) { + free(hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list); + hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = NULL; + } - if (ul_config_req != NULL) { - if (ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL) { - free(ul_config_req->ul_config_request_body.ul_config_pdu_list); - ul_config_req->ul_config_request_body.ul_config_pdu_list = NULL; + free(hi_dci0_req); + hi_dci0_req = NULL; } - free(ul_config_req); - ul_config_req = NULL; - } - - if (hi_dci0_req != NULL) { - if (hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list != NULL) { - free(hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list); - hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = NULL; + if (!sent_any) { + send_standalone_dummy(); } - - free(hi_dci0_req); - hi_dci0_req = NULL; } - if (!sent_any) { - send_standalone_dummy(); - } -} - -// Free UL_INFO messages -free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); -UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; -free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); -UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; -free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); -UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; -free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); -UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; -free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); -UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; -free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); -UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; -free(UL_INFO); -UL_INFO = NULL; - -// thread finished -free(arg); -return NULL; + // Free UL_INFO messages + free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); + UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; + free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); + UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; + free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); + UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; + free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); + UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; + free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); + UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; + free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); + UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; + free(UL_INFO); + UL_INFO = NULL; + // thread finished + free(arg); + return NULL; } /*! From b738f8a6a98976c04c01b8f7a230193523a341fd Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 11 Apr 2022 17:27:11 +0200 Subject: [PATCH 076/226] tackle code review remarks --- executables/nr-softmodem-common.h | 1 - executables/nr-ue.c | 14 ++------------ executables/softmodem-common.h | 1 - targets/RT/USER/lte-ru.c | 5 ++--- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index 47fd816db5..6e36dcf6c7 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -51,7 +51,6 @@ #define CONFIG_HLP_UEFO "set UE to enable estimation and compensation of frequency offset\n" #define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" #define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n" -#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" #define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" #define CONFIG_HLP_DORA "test gNB and UE with RA procedures\n" #define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n" diff --git a/executables/nr-ue.c b/executables/nr-ue.c index aef0370e53..02e92cbe0b 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -655,14 +655,6 @@ static void UE_synch(void *arg) { openair0_cfg[UE->rf_map.card].tx_freq[0]); UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); - //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]); - //UE->rfdevice.trx_stop_func(&UE->rfdevice); - // sleep(1); - /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { - LOG_E(HW,"Could not start the device\n"); - oai_exit=1; - }*/ - if (UE->UE_scan_carrier == 1) { UE->UE_scan_carrier = 0; } else { @@ -815,9 +807,9 @@ void processSlotRX(void *arg) { void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) { void *dummy_tx[UE->frame_parms.nb_antennas_tx]; - + int16_t dummy_tx_data[UE->frame_parms.nb_antennas_tx][2*writeBlockSize]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers for (int i=0; iframe_parms.nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(writeBlockSize*4); + dummy_tx[i]=dummy_tx_data[i]; AssertFatal( writeBlockSize == UE->rfdevice.trx_write_func(&UE->rfdevice, @@ -827,8 +819,6 @@ void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockS UE->frame_parms.nb_antennas_tx, 4),""); - for (int i=0; iframe_parms.nb_antennas_tx; i++) - free(dummy_tx[i]); } void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) { diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 48ce73149f..eb0c1a54f7 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -53,7 +53,6 @@ extern "C" #define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" -#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" #define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" #define CONFIG_HLP_DORA "test gNB and UE with RA procedures\n" #define CONFIG_HLP_SA "run gNB in standalone mode\n" diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index f6cf51f101..c1ffd7a292 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -835,8 +835,9 @@ void tx_rf(RU_t *ru, // in case of rfsim, we always enable tx because we need to feed rx of the opposite side // we write 1 single I/Q sample to trigger Rx (rfsim will fill gaps with 0 I/Q) void *dummy_tx[ru->frame_parms->nb_antennas_tx]; + int16_t dummy_tx_data[ru->frame_parms->nb_antennas_tx][2]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers for (int i=0; iframe_parms->nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(4); + dummy_tx[i]= dummy_tx_data[i]; AssertFatal( 1 == ru->rfdevice.trx_write_func(&ru->rfdevice, @@ -846,8 +847,6 @@ void tx_rf(RU_t *ru, ru->frame_parms->nb_antennas_tx, 4),""); - for (int i=0; iframe_parms->nb_antennas_tx; i++) - free(dummy_tx[i]); } } From 4ad71064b8a51176ec4c9536c2173ffda71df708 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 11 Apr 2022 19:29:45 +0200 Subject: [PATCH 077/226] review comments --- openair1/PHY/CODING/nr_rate_matching.c | 8 +-- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 7 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 13 ++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 66 ++++--------------- targets/ARCH/rfsimulator/apply_channelmod.c | 3 +- targets/ARCH/rfsimulator/rfsimulator.h | 2 +- 8 files changed, 31 insertions(+), 72 deletions(-) diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c index fbad79cad7..8c105c37e6 100644 --- a/openair1/PHY/CODING/nr_rate_matching.c +++ b/openair1/PHY/CODING/nr_rate_matching.c @@ -313,14 +313,12 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f) switch(Qm) { case 2: { - AssertFatal(E%4==0,""); + AssertFatal(E%2==0,""); int16_t *e1=e+(E/2); - int16_t *end=f+E-3; + int16_t *end=f+E-1; while( fF && pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) + return false; if (s->F) { *mac_subheader_len = sizeof(*l); *mac_ce_len = ntohs(l->L); @@ -128,6 +132,7 @@ static inline void getMacLen(uint8_t* pdu, uint16_t *mac_ce_len, uint16_t *mac_s *mac_subheader_len = sizeof(*s); *mac_ce_len = s->L; } + return true; } // BSR MAC CEs diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 47a6682f63..ab63303629 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3364,13 +3364,14 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, uint8_t rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID; LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", rx_lcid, pdu_len); + bool ret; switch(rx_lcid){ // MAC CE case DL_SCH_LCID_CCCH: // MSG4 RRC Setup 38.331 // variable length - getMacLen(pduP, &mac_len, &mac_subheader_len); - AssertFatal(pdu_len > mac_len, "The mac_len (%d) has an invalid size. PDU len = %d! \n", + ret=get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len); + AssertFatal(ret, "The mac_len (%d) has an invalid size. PDU len = %d! \n", mac_len, pdu_len); // Check if it is a valid CCCH message, we get all 00's messages very often @@ -3404,7 +3405,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, // 38.321 Ch6.1.3.14 // varialbe length - getMacLen(pduP, &mac_len, &mac_subheader_len); + get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len); break; case DL_SCH_LCID_RECOMMENDED_BITRATE: @@ -3508,10 +3509,8 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, // check if LCID is valid at current time. default: { - // check if LCID is valid at current time. - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return; - getMacLen(pduP, &mac_len, &mac_subheader_len); + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return; LOG_D(NR_MAC, "[UE %d] %4d.%2d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, slot, rx_lcid, gNB_index, mac_len); #if defined(ENABLE_MAC_PAYLOAD_DEBUG) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 422e40af7e..7e3f6c857a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1426,7 +1426,7 @@ void nr_schedule_ue_spec(module_id_t module_id, /* limit requested number of bytes to what preprocessor specified, or * such that TBS is full */ const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, - bufEnd-buf-+sizeof(NR_MAC_SUBHEADER_LONG)); + bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); tbs_size_t len = mac_rlc_data_req(module_id, rnti, module_id, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 67ab8aacc5..1955d91af6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -213,6 +213,7 @@ int nr_process_mac_pdu(module_id_t module_idP, int pdu_len) { + uint8_t done = 0; NR_UE_info_t *UE_info = &RC.nrmac[module_idP]->UE_info; @@ -279,16 +280,8 @@ int nr_process_mac_pdu(module_id_t module_idP, to be a partial PDU at the end of this buffer, so here we gracefully ignore that by returning 0. See: https://gitlab.eurecom.fr/oai/openairinterface5g/-/issues/534 */ - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return 0; - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return 0; - mac_ce_len= ntohs((NR_MAC_SUBHEADER_LONG *)pduP)->L); - mac_subheader_len = 3; - } + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return 0; /* Extract long BSR value */ ce_ptr = &pduP[mac_subheader_len]; NR_BSR_LONG *bsr_l = (NR_BSR_LONG *) ce_ptr; @@ -362,32 +355,16 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT: //38.321 section 6.1.3.9 // varialbe length - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return 0; - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return 0; - mac_ce_len = ntohs((NR_MAC_SUBHEADER_LONG *)pduP)->L); - mac_subheader_len = 3; - } + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return 0; /* Extract MULTI ENTRY PHR elements from single octet bitmap for PHR calculation */ break; case UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT: //38.321 section 6.1.3.9 // varialbe length - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return 0; - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return 0; - mac_ce_len = ntohs((NR_MAC_SUBHEADER_LONG *)pduP)->L); - mac_subheader_len = 3; - } + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return 0; /* Extract MULTI ENTRY PHR elements from four octets bitmap for PHR calculation */ break; @@ -398,18 +375,8 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_SRB1: case UL_SCH_LCID_SRB2: - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return 0; - if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){ - //mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return 0; - mac_subheader_len = 3; - mac_sdu_len = ntohs(NR_MAC_SUBHEADER_LONG *) pduP)->L); - } else { - mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - } + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return 0; rnti_t crnti = UE_info->rnti[UE_id]; int UE_idx = UE_id; @@ -486,19 +453,8 @@ int nr_process_mac_pdu(module_id_t module_idP, case UL_SCH_LCID_DTCH: // check if LCID is valid at current time. - if (pdu_len < sizeof(NR_MAC_SUBHEADER_SHORT)) - return 0; - if (((NR_MAC_SUBHEADER_SHORT *)pduP)->F) { - // mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8; - if (pdu_len < sizeof(NR_MAC_SUBHEADER_LONG)) - return 0; - mac_subheader_len = 3; - mac_sdu_len = ntohs((NR_MAC_SUBHEADER_LONG *)pduP)->L); - - } else { - mac_sdu_len = (NR_MAC_SUBHEADER_SHORT *)pduP)->L; - mac_subheader_len = 2; - } + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) + return 0; LOG_D(NR_MAC, "In %s: [UE %d] %d.%d : ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", __func__, diff --git a/targets/ARCH/rfsimulator/apply_channelmod.c b/targets/ARCH/rfsimulator/apply_channelmod.c index 6e26120e29..4ff5321e4d 100644 --- a/targets/ARCH/rfsimulator/apply_channelmod.c +++ b/targets/ARCH/rfsimulator/apply_channelmod.c @@ -52,7 +52,8 @@ either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes legacy: we regenerate each sub frame in UL, and each frame only in DL */ -void rxAddInput( c16_t *input_sig, c16_t *after_channel_sig, +void rxAddInput( const c16_t *input_sig, + c16_t *after_channel_sig, int rxAnt, channel_desc_t *channelDesc, int nbSamples, diff --git a/targets/ARCH/rfsimulator/rfsimulator.h b/targets/ARCH/rfsimulator/rfsimulator.h index 33583f2d32..e69d41fa6c 100644 --- a/targets/ARCH/rfsimulator/rfsimulator.h +++ b/targets/ARCH/rfsimulator/rfsimulator.h @@ -25,7 +25,7 @@ #define __RFSIMULATOR_H double gaussZiggurat(double mean, double variance); void tableNor(unsigned long seed); -void rxAddInput( c16_t *input_sig, +void rxAddInput( const c16_t *input_sig, c16_t *after_channel_sig, int rxAnt, channel_desc_t *channelDesc, From d642c74b66325b8d655c40044cbe081b4da7179a Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 12 Apr 2022 11:26:20 +0200 Subject: [PATCH 078/226] reintroducing RA logs to avoid CI test failure --- .../gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf | 1 - openair1/SCHED_NR/nr_prach_procedures.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf index 6fd04bf569..7b0e3eea22 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf @@ -38,7 +38,6 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" do_SRS = 1; diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 7b5b6d22ff..b0f59d5f47 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -173,7 +173,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot) { if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0+gNB->prach_thres)) { - LOG_D(NR_PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", + LOG_I(NR_PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", gNB->Mod_id, frame, slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index f297af27bb..7c8c8d12d7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -678,7 +678,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra->preamble_index = preamble_index; ra->beam_id = beam_index; - LOG_D(NR_MAC, + LOG_I(NR_MAC, "[gNB %d][RAPROC] CC_id %d Frame %d Activating Msg2 generation in frame %d, slot %d using RA rnti %x SSB " "index %u RA index %d\n", module_idP, @@ -795,7 +795,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t return; } - LOG_D(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", + LOG_I(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", module_idP, frame, slot, CC_id, sched_frame, sched_slot); nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][sched_slot]; @@ -1920,7 +1920,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra if(ra->msg3_dcch_dtch) { // If the UE used MSG3 to transfer a DCCH or DTCH message, then contention resolution is successful upon transmission of PDCCH - LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) CBRA procedure succeeded!\n", UE_id, ra->rnti); + LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) CBRA procedure succeeded!\n", UE_id, ra->rnti); nr_clear_ra_proc(module_idP, CC_id, frameP, ra); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; @@ -1953,12 +1953,12 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram if (harq->is_waiting == 0) { if (harq->round == 0) { if (stats->dlsch_errors == 0) { - LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); + LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; } else { - LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); + LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); } nr_clear_ra_proc(module_id, CC_id, frame, ra); From 2373b0215011357aa853bb9d53804a536977d226 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 12 Apr 2022 20:52:40 +0200 Subject: [PATCH 079/226] review remarks --- executables/nr-ue.c | 1 + targets/RT/USER/lte-ru.c | 1 + 2 files changed, 2 insertions(+) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 02e92cbe0b..aff56f583a 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -808,6 +808,7 @@ void processSlotRX(void *arg) { void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) { void *dummy_tx[UE->frame_parms.nb_antennas_tx]; int16_t dummy_tx_data[UE->frame_parms.nb_antennas_tx][2*writeBlockSize]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers + memset(dummy_tx_data, 0, sizeof(dummy_tx_data)); for (int i=0; iframe_parms.nb_antennas_tx; i++) dummy_tx[i]=dummy_tx_data[i]; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index c1ffd7a292..cee15ef48b 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -836,6 +836,7 @@ void tx_rf(RU_t *ru, // we write 1 single I/Q sample to trigger Rx (rfsim will fill gaps with 0 I/Q) void *dummy_tx[ru->frame_parms->nb_antennas_tx]; int16_t dummy_tx_data[ru->frame_parms->nb_antennas_tx][2]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers + memset(dummy_tx_data,0,sizeof(dummy_tx_data)); for (int i=0; iframe_parms->nb_antennas_tx; i++) dummy_tx[i]= dummy_tx_data[i]; From 0270b7b1fb8f213d81785f0f7cc7c2a4a8e59e6d Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 14 Apr 2022 15:49:29 +0100 Subject: [PATCH 080/226] Move RRC processing timer implementation from RRC to MAC --- openair1/SIMULATION/NR_PHY/dlsim.c | 4 +- openair1/SIMULATION/NR_PHY/ulsim.c | 4 +- openair2/GNB_APP/gnb_config.c | 4 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 3 - openair2/LAYER2/NR_MAC_gNB/config.c | 23 +++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 3 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 8 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 20 +++- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 1 - .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 9 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 +- openair2/RRC/NR/L2_nr_interface.c | 11 -- openair2/RRC/NR/nr_rrc_defs.h | 5 - openair2/RRC/NR/rrc_gNB.c | 113 ++++++++++++------ openair2/RRC/NR/rrc_gNB_nsa.c | 6 +- 16 files changed, 142 insertions(+), 79 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 1de8d6ced4..b15f649d3e 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -827,9 +827,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL); + rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL, 0); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup, 0); // reset preprocessor to the one of DLSIM after it has been set during // rrc_mac_config_req_gNB gNB_mac->pre_processor_dl = nr_dlsim_preprocessor; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 09499248b2..e4c693d602 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -751,9 +751,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); + rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL, 0); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup, 0); frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 434a2896de..7751172cdb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2066,8 +2066,8 @@ void configure_gnb_du_mac(int inst) { NULL, 0, 0, // rnti - (NR_CellGroupConfig_t *)NULL - ); + NULL, + 0); } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 2d69e0d64f..0f2cb42b88 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -203,7 +203,4 @@ void nr_mac_gNB_rrc_ul_failure_reset(const module_id_t Mod_instP, const frame_t frameP, const sub_frame_t subframeP, const rnti_t rntiP); - -void nr_mac_gNB_enable_rrc_processing_timer_req(const module_id_t Mod_instP, const rnti_t rntiP); - #endif diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index abdca03faa..4f19a313ae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -449,10 +449,6 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts } -void nr_rrc_mac_schedule_ue_enabled(module_id_t module_id, rnti_t rnti, bool schedule_enabled) { - const int UE_id = find_nr_UE_id(module_id,rnti); - RC.nrmac[module_id]->UE_info.UE_sched_ctrl[UE_id].schedule_enabled = schedule_enabled; -} int rrc_mac_config_req_gNB(module_id_t Mod_idP, int ssb_SubcarrierOffset, @@ -465,7 +461,23 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, NR_BCCH_DL_SCH_Message_t *sib1, int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup) { + NR_CellGroupConfig_t *CellGroup, + uint32_t rrc_reconfiguration_delay) { + + if (scc && rrc_reconfiguration_delay > 0) { + const int UE_id = find_nr_UE_id(Mod_idP,rnti); + if (UE_id >= 0) { + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer == 0) { + const uint16_t sf_ahead = (uint16_t) ceil((float)6/(0x01<<(*scc->ssbSubcarrierSpacing))); + const uint16_t sl_ahead = sf_ahead * (0x01<<(*scc->ssbSubcarrierSpacing)); + sched_ctrl->rrc_processing_timer = (rrc_reconfiguration_delay << (*scc->ssbSubcarrierSpacing)) + sl_ahead; + LOG_I(NR_MAC, "Activating RRC processing timer for UE %d\n", UE_id); + } + } + return 0; + } if (scc != NULL ) { AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present); @@ -695,6 +707,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, sched_ctrl->maxL = 2; } } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 540198a22a..ecc2ef0cff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -346,6 +346,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output); } + // This updates the timers running at MAC layer + nr_mac_update_timers(module_idP, frame, slot); + // This schedules MIB schedule_nr_mib(module_idP, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index cb68ea0324..c76e6d238a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1947,10 +1947,12 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; - // Pause scheduling according to: + const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, + RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, + sib1); // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - sched_ctrl->schedule_enabled = false; - nr_mac_gNB_enable_rrc_processing_timer_req(module_id, ra->rnti); + sched_ctrl->rrc_processing_timer = (10 << genericParameters->subcarrierSpacing); // RRCSetup 10 ms } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 9b3b02d0d4..f72ccaf6e5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -490,7 +490,7 @@ void nr_store_dlsch_buffer(module_id_t module_id, const uint16_t rnti = UE_info->rnti[UE_id]; LOG_D(NR_MAC, "In %s: UE %d/%x: LCID %d\n", __FUNCTION__, UE_id, rnti, lcid); - if(lcid == DL_SCH_LCID_DTCH && sched_ctrl->schedule_enabled == false) { + if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) { continue; } @@ -498,7 +498,7 @@ void nr_store_dlsch_buffer(module_id_t module_id, sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, rnti, module_id, - frame, + frame, slot, ENB_FLAG_YES, MBMS_FLAG_NO, @@ -1056,6 +1056,22 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(module_id_t module_id, int CC_id) return nr_fr1_dlsch_preprocessor; } +void nr_mac_update_timers(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + const NR_list_t *UE_list = &UE_info->list; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer--; + if (sched_ctrl->rrc_processing_timer == 0) { + LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); + } + } + } +} + void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, sub_frame_t slot) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 67609ad105..6f17556c91 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2312,7 +2312,6 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG sched_ctrl->pucch_consecutive_dtx_cnt = 0; sched_ctrl->pusch_consecutive_dtx_cnt = 0; sched_ctrl->ul_failure = 0; - sched_ctrl->schedule_enabled = true; sched_ctrl->sched_srs.frame = -1; sched_ctrl->sched_srs.slot = -1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 5a4d1d4d1b..e6637f266a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1252,7 +1252,7 @@ void pf_ul(module_id_t module_id, const bool do_sched = nr_UE_is_to_be_scheduled(module_id, 0, UE_id, sched_pusch->frame, sched_pusch->slot); LOG_D(NR_MAC,"pf_ul: do_sched UE %d => %s\n",UE_id,do_sched ? "yes" : "no"); - if ( (B == 0 && !do_sched) || (sched_ctrl->schedule_enabled == false) ) { + if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) { continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index afe1bb47f0..da2a59a568 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -46,8 +46,6 @@ void config_common(int Mod_idP, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc); -void nr_rrc_mac_schedule_ue_enabled(module_id_t module_id, rnti_t rnti, bool schedule_enabled); - int rrc_mac_config_req_gNB(module_id_t Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, @@ -59,13 +57,18 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, NR_BCCH_DL_SCH_Message_t *sib1, int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup); + NR_CellGroupConfig_t *CellGroup, + uint32_t rrc_reconfiguration_delay); void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, frame_t frameP, sub_frame_t subframeP); +void nr_mac_update_timers(module_id_t module_id, + frame_t frame, + sub_frame_t slot); + void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_rxP, sub_frame_t slot_rxP); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 9156d45865..f7282045b9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -646,12 +646,13 @@ typedef struct { /// UL HARQ processes that await retransmission NR_list_t retrans_ul_harq; NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information - /// Flag to indicate if MAC scheduling is enabled or disabled by RRC (e.g. during RRC processing time) - bool schedule_enabled; /// number of active DL LCs uint8_t dl_lc_num; /// order in which DLSCH scheduler should allocate LCs uint8_t dl_lc_ids[NR_MAX_NUM_LCID]; + + /// Timer for RRC processing procedures + uint32_t rrc_processing_timer; } NR_UE_sched_ctrl_t; typedef struct { diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index c22a5bd71f..e30b55cc94 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -392,14 +392,3 @@ void nr_mac_gNB_rrc_ul_failure_reset(const module_id_t Mod_instP, LOG_W(RRC,"Frame %d, Subframe %d: UL failure reset: UE %x unknown \n",frameP,subframeP,rntiP); } } - -void nr_mac_gNB_enable_rrc_processing_timer_req(const module_id_t Mod_instP, const rnti_t rntiP) { - struct rrc_gNB_ue_context_s *ue_context_p = NULL; - ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[Mod_instP], rntiP); - if (ue_context_p != NULL) { - ue_context_p->ue_context.nr_rrc_processing_timer = 1; - ue_context_p->ue_context.nr_rrc_processing_delay = NR_RRC_PROCESSING_DELAY_MS; - } else { - LOG_E(NR_RRC,"%s: Unknown RNTI 0x%04x\n", __FUNCTION__, rntiP); - } -} \ No newline at end of file diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e37e932220..268168750c 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -96,9 +96,6 @@ typedef struct nr_uid_linear_allocator_s { #define PROTOCOL_NR_RRC_CTXT_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_NR_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) -// Delay to take in consideration for sl_ahead value -#define TX_SL_AHEAD_DELAY 3 - // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs #define NR_RRC_PROCESSING_DELAY_MS 10 @@ -379,8 +376,6 @@ typedef struct gNB_RRC_UE_s { //GTPV1 F1-U TUNNELS uint32_t incoming_teid[S1AP_MAX_E_RAB]; - uint32_t nr_rrc_processing_timer; - uint32_t nr_rrc_processing_delay; uint32_t ul_failure_timer; uint32_t ue_release_timer; uint32_t ue_release_timer_thres; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index cbb963693f..a7e6e49052 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -140,16 +140,6 @@ void openair_nr_rrc_on(const protocol_ctxt_t *const ctxt_pP) { RC.nrrrc[ctxt_pP->module_id]->carrier.Srb0.Active = 1; } -void enable_nr_rrc_processing_timer(module_id_t module_id, - rrc_gNB_ue_context_t *ue_context_pP, - uint32_t delay_ms) { - if (NODE_IS_DU(RC.nrrrc[module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[module_id]->node_type)) { - ue_context_pP->ue_context.nr_rrc_processing_timer = 1; - ue_context_pP->ue_context.nr_rrc_processing_delay = delay_ms; - nr_rrc_mac_schedule_ue_enabled(module_id, ue_context_pP->ue_context.rnti, false); - } -} - ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// @@ -186,7 +176,8 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration rrc->carrier.siblock1, 0, 0, // WIP hardcoded rnti - NULL); + NULL, + 0); } /* set flag to indicate that cell information is configured. This is required @@ -295,7 +286,8 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, NULL, 0, ue_context_pP->ue_context.rnti, - cgc); + cgc, + 0); nr_rrc_rlc_config_asn1_req(ctxt_pP, ue_context_pP->ue_context.SRB_configList, @@ -483,7 +475,8 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( rrc_instance_p->carrier.siblock1, 0, ue_context_pP->ue_context.rnti, - NULL); + NULL, + 0); LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", @@ -735,12 +728,24 @@ rrc_gNB_generate_defaultRRCReconfiguration( NULL, ue_p->masterCellGroup); - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS); - free(ue_context_pP->ue_context.nas_pdu.buffer); LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + rrc->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + rrc->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_PROCESSING_DELAY_MS); + /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -1005,10 +1010,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( &rrc->configuration, NULL, cellGroupConfig); + LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS); - - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + rrc->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + rrc->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_PROCESSING_DELAY_MS); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1181,11 +1197,22 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL, NULL, NULL); - - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_PROCESSING_DELAY_MS); + /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { if (ue_context_pP->ue_context.modify_pdusession[i].param.nas_pdu.buffer != NULL) { @@ -1286,12 +1313,24 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( NULL, NULL); - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS); - ue_context_pP->ue_context.pdu_session_release_command_flag = 1; LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_PROCESSING_DELAY_MS); + /* Free all NAS PDUs */ if (nas_length > 0) { /* Free the NAS PDU buffer and invalidate it */ @@ -1399,7 +1438,8 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, 0, ue_context_pP->ue_context.rnti, - ue_context_pP->ue_context.masterCellGroup); + ue_context_pP->ue_context.masterCellGroup, + 0); LOG_D(NR_RRC,"Configuring RLC DRBs/SRBs for UE %x\n",ue_context_pP->ue_context.rnti); nr_rrc_rlc_config_asn1_req(ctxt_pP, SRB_configList, // NULL, @@ -1840,10 +1880,22 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( NULL, NULL); - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS); - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_PROCESSING_DELAY_MS); + /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -3459,15 +3511,6 @@ void nr_rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { get_ul_mimo_layers(RC.nrrrc[0],ue_context_p->ue_context.UE_Capability_nr)); } } - - if (ue_context_p->ue_context.nr_rrc_processing_timer > 0) { - ue_context_p->ue_context.nr_rrc_processing_timer++; - if (ue_context_p->ue_context.nr_rrc_processing_timer > ue_context_p->ue_context.nr_rrc_processing_delay) { - ue_context_p->ue_context.nr_rrc_processing_timer = 0; - nr_rrc_mac_schedule_ue_enabled(ctxt_pP->module_id, ue_context_p->ue_context.rnti, true); - } - } - if (ue_context_p->ue_context.ul_failure_timer > 0) { ue_context_p->ue_context.ul_failure_timer++; diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index fb8de46953..2685f3ba35 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -356,7 +356,8 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, 1, // add_ue flag ue_context_p->ue_id_rnti, - ue_context_p->ue_context.secondaryCellGroup); + ue_context_p->ue_context.secondaryCellGroup, + 0); } else { rrc_mac_config_req_gNB(rrc->module_id, rrc->configuration.ssb_SubcarrierOffset, @@ -369,7 +370,8 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, 1, // add_ue flag ue_context_p->ue_id_rnti, - ue_context_p->ue_context.secondaryCellGroup); + ue_context_p->ue_context.secondaryCellGroup, + 0); } if(m == NULL){ From 7b5d8de65ff24e3e1f414336c21241a107f3fac2 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 14 Apr 2022 15:52:54 +0100 Subject: [PATCH 081/226] Remove sib1_tda from configuration files to use the default value --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 1 - targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - .../CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - 7 files changed, 7 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..92d1ce432c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -48,7 +48,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 256d724f3f..f95bdf91ae 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -38,7 +38,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 726e43d7ad..74f6c34f57 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - sib1_tda = 0; servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 7e2db64aaa..d124c5692f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..ff64fe718a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -36,7 +36,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 950e9c1d38..1bc6de3bfe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -35,7 +35,6 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; - sib1_tda = 0; do_SRS = 1; ul_prbblacklist = "51,52,53,54" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1dc903b811..a0cee6f9ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { From 815a15e544ccb25bf46d6a3181deb718f3a91077 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 14 Apr 2022 17:43:02 +0200 Subject: [PATCH 082/226] fixes for SR in pucch0 --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 20 ++++++++++++++------ openair1/PHY/defs_gNB.h | 2 -- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 50c3b62f50..d1f7ff7c6c 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -298,7 +298,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, xr[aa][l][n2+1]+=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); #ifdef DEBUG_NR_PUCCH_RX printf("x (%d,%d), r%d.%d (%d,%d), xr (%d,%d)\n", - x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); + x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); #endif } } @@ -390,7 +390,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, index=maxpos; uci_stats->pucch0_n00 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]]; uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; - LOG_D(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); + LOG_I(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); // estimate CQI for MAC (from antenna port 0 only) int max_n0 = uci_stats->pucch0_n00>uci_stats->pucch0_n01 ? uci_stats->pucch0_n00:uci_stats->pucch0_n01; int SNRtimes10,sigenergy=0; @@ -422,11 +422,12 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, if (pucch_pdu->bit_len_harq==0) { uci_pdu->harq = NULL; uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); - uci_pdu->sr->sr_confidence_level = no_conf ? 1 : 0; + uci_pdu->sr->sr_confidence_level = (SNRtimes10 > uci_stats->pucch0_thres) ? 1 : 0; uci_stats->pucch0_sr_trials++; - if (xrtmag_dBtimes10>(10*gNB->measurements.n0_power_tot_dB)) { + if (xrtmag_dBtimes10>10*max_n0) { uci_pdu->sr->sr_indication = 1; uci_stats->pucch0_positive_SR++; + LOG_D(PHY,"PUCCH0 got positive SR. Cumulative number of positive SR %d\n", uci_stats->pucch0_positive_SR); } else { uci_pdu->sr->sr_indication = 0; } @@ -445,7 +446,10 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_indication = (index>1) ? 1 : 0; uci_pdu->sr->sr_confidence_level = no_conf ? 1 : 0; - uci_stats->pucch0_positive_SR++; + if(uci_pdu->sr->sr_indication == 1 && uci_pdu->sr->sr_confidence_level == 0) { + uci_stats->pucch0_positive_SR++; + LOG_D(PHY,"PUCCH0 got positive SR. Cumulative number of positive SR %d\n", uci_stats->pucch0_positive_SR); + } } uci_stats->pucch01_trials++; } @@ -463,6 +467,10 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_indication = (index>3) ? 1 : 0; uci_pdu->sr->sr_confidence_level = (no_conf) ? 1 : 0; + if(uci_pdu->sr->sr_indication == 1 && uci_pdu->sr->sr_confidence_level == 0) { + uci_stats->pucch0_positive_SR++; + LOG_D(PHY,"PUCCH0 got positive SR. Cumulative number of positive SR %d\n", uci_stats->pucch0_positive_SR); + } } } } @@ -1671,7 +1679,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, LOG_D(PHY,"metric %d dB\n",corr_dB); } - // estimate CQI for MAC (from antenna port 0 only) + // estimate CQI for MAC (from antenna port 0 only) int SNRtimes10 = dB_fixed_times10(signal_energy_nodc(&rxdataF[0][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[0]], 12*pucch_pdu->prb_size)) - (10*gNB->measurements.n0_power_tot_dB); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 7b655c023a..f382de73aa 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -661,8 +661,6 @@ typedef struct { unsigned int n0_power_tot; //! estimated avg noise power (dB) unsigned int n0_power_tot_dB; - //! estimated avg noise power (dB) - int n0_power_tot_dBm; //! estimated avg noise power per RB per RX ant (lin) unsigned int n0_subband_power[MAX_NUM_RU_PER_gNB][275]; //! estimated avg noise power per RB per RX ant (dB) From ca51ba7d3f860df32b256df2a4b5c2b55d14b929 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 14 Apr 2022 19:30:22 +0200 Subject: [PATCH 083/226] ignoring PUCCH2 TPC for now --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 3 ++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index d1f7ff7c6c..bcf743b560 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -390,7 +390,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, index=maxpos; uci_stats->pucch0_n00 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]]; uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; - LOG_I(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); + LOG_D(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); // estimate CQI for MAC (from antenna port 0 only) int max_n0 = uci_stats->pucch0_n00>uci_stats->pucch0_n01 ? uci_stats->pucch0_n00:uci_stats->pucch0_n01; int SNRtimes10,sigenergy=0; @@ -1680,6 +1680,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, } // estimate CQI for MAC (from antenna port 0 only) + // TODO this computation is wrong -> to be ignored at MAC for now int SNRtimes10 = dB_fixed_times10(signal_energy_nodc(&rxdataF[0][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[0]], 12*pucch_pdu->prb_size)) - (10*gNB->measurements.n0_power_tot_dB); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index e21d1e50f7..3eda061959 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1493,10 +1493,11 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; // tpc (power control) - sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, - uci_234->ul_cqi, - 30); - sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640; + // TODO PUCCH2 SNR computation is not correct -> ignore the following + //sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, + // uci_234->ul_cqi, + // 30); + //sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640; if ((uci_234->pduBitmap >> 1) & 0x01) { // iterate over received harq bits From 8b0be9cf87708f9f5976ff239daa8d719d17dae4 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 20 Jan 2022 15:45:43 +0100 Subject: [PATCH 084/226] nr rlc: speedup ack/nack reception The code completely changed, expect problems. --- openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 850 +++++++++++---------- openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h | 3 - openair2/LAYER2/nr_rlc/nr_rlc_sdu.c | 11 +- openair2/LAYER2/nr_rlc/nr_rlc_sdu.h | 7 +- openair2/LAYER2/nr_rlc/tests/test14.txt.gz | Bin 792 -> 799 bytes openair2/LAYER2/nr_rlc/tests/test15.txt.gz | Bin 546 -> 554 bytes 6 files changed, 441 insertions(+), 430 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index af8cb5715a..e86e7c7d05 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -103,36 +103,6 @@ static int segment_already_received(nr_rlc_entity_am_t *entity, return size <= 0; } -static void consider_retransmission(nr_rlc_entity_am_t *entity, - nr_rlc_sdu_segment_t *cur, int update_retx) -{ - if (update_retx) - cur->sdu->retx_count++; - - /* let's report max RETX reached for all retx_count >= max_retx_threshold - * (specs say to report if retx_count == max_retx_threshold). - * Upper layers should react (radio link failure), so no big deal actually. - */ - if (update_retx && cur->sdu->retx_count >= entity->max_retx_threshold) { - entity->common.max_retx_reached(entity->common.max_retx_reached_data, - (nr_rlc_entity_t *)entity); - } - - /* let's put in retransmit list even if we are over max_retx_threshold. - * upper layers should deal with this condition, internally it's better - * for the RLC code to keep going with this segment (we only remove - * a segment that was ACKed) - */ - LOG_D(RLC, "RLC segment to be added at the ReTx list \n"); - nr_rlc_sdu_segment_list_append(&entity->retransmit_list, - &entity->retransmit_end, - cur); - - /* update buffer status */ - entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur) - + cur->size; -} - /* checks that all the bytes of the SDU sn have been received (but SDU * has not been already processed) */ @@ -315,81 +285,6 @@ static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu) } } -static void process_received_ack(nr_rlc_entity_am_t *entity, int ack_sn) -{ - nr_rlc_sdu_segment_t head; - nr_rlc_sdu_segment_t *cur; - nr_rlc_sdu_segment_t *prev; - unsigned char sn_set[32768]; /* used to dec retx_count only once per sdu */ - - memset(sn_set, 0, 32768); - -#define IS_SN_SET(b) (sn_set[(b)/8] & (1 << ((b) % 8))) -#define SET_SN(b) do { sn_set[(b)/8] |= (1 << ((b) % 8)); } while (0) - - /* put SDUs from wait and retransmit lists with SN < 'ack_sn' to ack_list */ - - /* process wait list */ - head.next = entity->wait_list; - prev = &head; - cur = entity->wait_list; - while (cur != NULL) { - if (sn_compare_tx(entity, cur->sdu->sn, ack_sn) < 0) { - /* remove from wait list */ - prev->next = cur->next; - /* put the PDU in the ack list */ - entity->ack_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, - entity->ack_list, cur); - entity->wait_end = prev; - cur = prev->next; - } else { - entity->wait_end = cur; - prev = cur; - cur = cur->next; - } - } - entity->wait_list = head.next; - if (entity->wait_list == NULL) - entity->wait_end = NULL; - - /* process retransmit list */ - head.next = entity->retransmit_list; - prev = &head; - cur = entity->retransmit_list; - while (cur != NULL) { - if (sn_compare_tx(entity, cur->sdu->sn, ack_sn) < 0) { - /* dec. retx_count in case we put this segment back in retransmit list - * in 'process_received_nack' - * do it only once per SDU - */ - if (!IS_SN_SET(cur->sdu->sn)) { - cur->sdu->retx_count--; - SET_SN(cur->sdu->sn); - } - /* remove from retransmit list */ - prev->next = cur->next; - /* update buffer status */ - entity->common.bstatus.retx_size -= compute_pdu_header_size(entity, cur) - + cur->size; - /* put the PDU in the ack list */ - entity->ack_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, - entity->ack_list, cur); - entity->retransmit_end = prev; - cur = prev->next; - } else { - entity->retransmit_end = cur; - prev = cur; - cur = cur->next; - } - } - entity->retransmit_list = head.next; - if (entity->retransmit_list == NULL) - entity->retransmit_end = NULL; - -#undef IS_BIT_SET -#undef SET_BIT -} - static int so_overlap(int s1, int e1, int s2, int e2) { if (s1 < s2) { @@ -402,136 +297,375 @@ static int so_overlap(int s1, int e1, int s2, int e2) return 0; } -static void process_nack_sn(nr_rlc_entity_am_t *entity, int nack_sn, - int so_start, int so_end, unsigned char *sn_set) -{ - /* put all SDU segments with SN == 'sn' and with an overlapping so start/end - * to the retransmit list - * source lists are ack list and wait list. - * Not sure if we should consider wait list, isn't the other end supposed - * to only NACK SNs lower than the ACK SN sent in the status PDU, in which - * case all potential SDU segments should all be in ack list when calling - * the current function? in doubt let's accept anything and thus process - * also wait list. - */ - nr_rlc_sdu_segment_t head; - nr_rlc_sdu_segment_t *cur; - nr_rlc_sdu_segment_t *prev; - -#define IS_SN_SET(b) (sn_set[(b)/8] & (1 << ((b) % 8))) -#define SET_SN(b) do { sn_set[(b)/8] |= (1 << ((b) % 8)); } while (0) - - /* check that tx_next_ack <= sn < tx_next */ - if (!(sn_compare_tx(entity, entity->tx_next_ack, nack_sn) <= 0 && - sn_compare_tx(entity, nack_sn, entity->tx_next) < 0)) - return; - - /* process wait list */ - head.next = entity->wait_list; - prev = &head; - cur = entity->wait_list; - while (cur != NULL) { - if (cur->sdu->sn == nack_sn && - so_overlap(so_start, so_end, cur->so, cur->so + cur->size - 1)) { - /* remove from wait list */ - prev->next = cur->next; - cur->next = NULL; - /* consider the SDU segment for retransmission */ - consider_retransmission(entity, cur, !IS_SN_SET(cur->sdu->sn)); - SET_SN(cur->sdu->sn); - entity->wait_end = prev; - cur = prev->next; - } else { - entity->wait_end = cur; - prev = cur; - cur = cur->next; - } - } - entity->wait_list = head.next; - if (entity->wait_list == NULL) - entity->wait_end = NULL; - - /* process ack list */ - head.next = entity->ack_list; - prev = &head; - cur = entity->ack_list; - while (cur != NULL) { - if (cur->sdu->sn == nack_sn && - so_overlap(so_start, so_end, cur->so, cur->so + cur->size - 1)) { - /* remove from ack list */ - prev->next = cur->next; - cur->next = NULL; - /* consider the SDU segment for retransmission */ - consider_retransmission(entity, cur, !IS_SN_SET(cur->sdu->sn)); - SET_SN(cur->sdu->sn); - cur = prev->next; - } else { - prev = cur; - cur = cur->next; - } - } - entity->ack_list = head.next; - -#undef IS_BIT_SET -#undef SET_BIT -} - -static void process_received_nack(nr_rlc_entity_am_t *entity, int nack_sn, - int so_start, int so_end, int range, - unsigned char *sn_set) +static void process_control_pdu(nr_rlc_entity_am_t *entity, + char *buffer, int size) { +#define R(d) do { if (nr_rlc_pdu_decoder_in_error(&d)) goto err; } while (0) + nr_rlc_pdu_decoder_t decoder; int i; + int cpt; + int ack_sn; + int nack_sn; + int e1; + int e2; + int e3; + int so_start; + int so_end; + int range; + int prev_nack_sn = -1; + int prev_so_start; + int prev_so_end; + int tx_next_ack; + nr_rlc_sdu_segment_t *cur_wait_list; + nr_rlc_sdu_segment_t *prev_wait_list; + nr_rlc_sdu_segment_t *end_wait_list = NULL; + nr_rlc_sdu_segment_t head_wait_list; + nr_rlc_sdu_segment_t *cur_retransmit_list; + nr_rlc_sdu_segment_t *new_retransmit_list; + nr_rlc_sdu_segment_t head_retransmit_list; - for (i = 0; i < range; i++) - process_nack_sn(entity, (nack_sn + i) % entity->sn_modulus, - i == 0 ? so_start : 0, - i == range - 1 ? so_end : -1, - sn_set); -} + head_wait_list.next = entity->wait_list; + cur_wait_list = entity->wait_list; + prev_wait_list = &head_wait_list; -static int sdu_segment_in_ack_list_full(nr_rlc_sdu_segment_t *sdu) -{ - int target_count = sdu->sdu->ref_count; - int actual_count = 0; - int sn = sdu->sdu->sn; + head_retransmit_list.next = NULL; + cur_retransmit_list = entity->retransmit_list; + new_retransmit_list = &head_retransmit_list; - while (sdu != NULL && sdu->sdu->sn == sn) { - actual_count++; - sdu = sdu->next; + nr_rlc_pdu_decoder_init(&decoder, buffer, size); + nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); /* dc */ + + cpt = nr_rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); + if (cpt != 0) { + LOG_E(RLC, "%s:%d:%s: warning: discard PDU, CPT not 0 (%d)\n", + __FILE__, __LINE__, __FUNCTION__, cpt); + goto err; + } + ack_sn = nr_rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); + e1 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + /* r bits */ + if (entity->sn_field_length == 18) { + nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + } else { + nr_rlc_pdu_decoder_get_bits(&decoder, 7); R(decoder); } - return actual_count == target_count; -} - -static void finalize_ack_nack_processing(nr_rlc_entity_am_t *entity) -{ - nr_rlc_sdu_segment_t *cur = entity->ack_list; - int sn; - - /* - send indication of successful delivery for all consecutive acked SDUs - * starting from tx_next_ack. Also free them. - * - update tx_next_ack to the next SN not acked yet + /* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' - check ACK case (NACK done below) */ - /* todo: send indication of successful delivery as soon as possible as - * the specs say (38.322 5.2.3.1.1). As the code is, if we receive - * ack for SN+2 we won't indicate successful delivery before - * SN+1 has been indicated. + if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0) + entity->t_poll_retransmit_start = 0; + + while (e1) { + nack_sn = nr_rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); + e1 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + e2 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + e3 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + /* r bits */ + if (entity->sn_field_length == 18) { + nr_rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); + } else { + nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + } + if (e2) { + so_start = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder); + so_end = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder); + } else { + so_start = 0; + so_end = 0xffff; + } + if (e3) { + range = nr_rlc_pdu_decoder_get_bits(&decoder, 8); R(decoder); + } else { + range = 1; + } + /* special value 0xffff indicates 'all bytes to the end' */ + if (so_end == 0xffff) + so_end = -1; + + /* process nacks */ + for (i = 0; i < range; i++) { + int cur_nack_sn = (nack_sn + i) % entity->sn_modulus; + int cur_so_start = i == 0 ? so_start : 0; + int cur_so_end = i == range - 1 ? so_end : -1; + + /* check that current nack is > previous nack and <= ack + * if not then skip it and all following nacks, and + * do not touch t_poll_retransmit + */ + if (prev_nack_sn != -1) { + int cmp = sn_compare_tx(entity, cur_nack_sn, prev_nack_sn); + if (cmp < 0 + || (cmp == 0 + && (prev_so_end == -1 + || cur_so_start <= prev_so_end))) { + LOG_E(RLC, "%s:%d:%s: bad NACK (nack sn %d so start/end %d/%d, previous nack sn %d so start/end %d/%d), skip it and all following NACKs\n", + __FILE__, __LINE__, __FUNCTION__, + cur_nack_sn, cur_so_start, cur_so_end, + prev_nack_sn, prev_so_start, prev_so_end); + goto nacks_done; + } + } + if (sn_compare_tx(entity, cur_nack_sn, ack_sn) > 0) { + LOG_E(RLC, "%s:%d:%s: bad NACK (nack %d ack %d), skip it and all following NACKs\n", + __FILE__, __LINE__, __FUNCTION__, + cur_nack_sn, ack_sn); + goto nacks_done; + } + +process_next_pdu: + /* process smallest SN either from wait_list or retransmit list */ + if (cur_wait_list == NULL && cur_retransmit_list == NULL) + goto lists_over; + if (cur_wait_list == NULL) + goto process_retransmit_list_head; + if (cur_retransmit_list == NULL) + goto process_wait_list_head; + if (cur_wait_list->sdu->sn < cur_retransmit_list->sdu->sn + || (cur_wait_list->sdu->sn == cur_retransmit_list->sdu->sn && + cur_wait_list->so < cur_retransmit_list->so)) + goto process_wait_list_head; + goto process_retransmit_list_head; + +process_wait_list_head: + /* if nack overlaps with current segment, put it in retransmit list */ + if (cur_wait_list->sdu->sn == cur_nack_sn + && so_overlap(cur_so_start, cur_so_end, + cur_wait_list->so, + cur_wait_list->so + cur_wait_list->size - 1)) { + prev_wait_list->next = cur_wait_list->next; + if (cur_wait_list == entity->wait_end) + end_wait_list = prev_wait_list; + cur_wait_list->next = NULL; + new_retransmit_list->next = cur_wait_list; + new_retransmit_list = cur_wait_list; + /* increase retx count. Don't care about segmentation, so maybe we + * increase too much. + */ + cur_wait_list->sdu->retx_count++; + /* report max RETX reached for all retx_count >= max_retx_threshold + * (specs say to report if retx_count == max_retx_threshold). + * Upper layers should react (radio link failure), so no big deal. + * We deal with segmentation by requiring + * retx_count >= max_retx_threshold * number of segments. + * We may report max RETX reached too late/early. To be refined if + * this is a problem. + */ + if (cur_wait_list->sdu->retx_count + >= entity->max_retx_threshold * cur_wait_list->sdu->ref_count) + entity->common.max_retx_reached(entity->common.max_retx_reached_data, + (nr_rlc_entity_t *)entity); + /* update buffer status */ + entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur_wait_list) + + cur_wait_list->size; + /* and go process the next pdu, still for the current nack */ + cur_wait_list = prev_wait_list->next; + goto process_next_pdu; + } + + /* if current segment SN > current NACK, we can't classify it yet */ + if (sn_compare_tx(entity, cur_wait_list->sdu->sn, cur_nack_sn) > 0 + || (cur_wait_list->sdu->sn == cur_nack_sn + && cur_wait_list->so > cur_so_start)) + goto done_nack; + + /* if current segment is acked, free it, indicate successful delivery + * if fully acked + */ + if (sn_compare_tx(entity, cur_wait_list->sdu->sn, ack_sn) < 0) { + nr_rlc_sdu_segment_t *cur = cur_wait_list; + int upper_layer_id = cur->sdu->upper_layer_id; + int sdu_size = cur->sdu->size; + cur_wait_list = cur_wait_list->next; + prev_wait_list->next = cur_wait_list; + if (cur_wait_list == entity->wait_end) + end_wait_list = prev_wait_list; + if (nr_rlc_free_sdu_segment(cur)) { + entity->tx_size -= sdu_size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (nr_rlc_entity_t *)entity, upper_layer_id); + } + goto process_next_pdu; + } + + /* if current segment SN > ack_sn, we're done with this list */ + if (sn_compare_tx(entity, cur_wait_list->sdu->sn, ack_sn) > 0) { + cur_wait_list = NULL; + goto process_next_pdu; + } + + /* current segment SN == ack_sn, skip this segment and move to the next. + * Not sure if correct, can we get a nack_sn == ack_sn? 38.322 5.3.4 says + * "set the ACK_SN to the SN of the next not received RLC SDU which is + * not indicated as missing in the resulting STATUS PDU." Is it okay to + * receive some NACK for a given SN and an ACK == this SN? I can see a + * case where it's possible (only parts of an SN were received and the + * TB is too small to report the several NACKs for this SN, then we + * can't set ACK = SN+1 but in this case, shouldn't we skip sending + * NACKs for this SN and only send ACK = SN? our current implementation + * does send both NACKs and ACK, see function generate_status()). + */ + prev_wait_list = cur_wait_list; + cur_wait_list = cur_wait_list->next; + goto process_next_pdu; + +process_retransmit_list_head: + /* if nack overlaps with current segment, leave it in retransmit list */ + if (cur_retransmit_list->sdu->sn == cur_nack_sn + && so_overlap(cur_so_start, cur_so_end, + cur_retransmit_list->so, + cur_retransmit_list->so + cur_retransmit_list->size - 1)) { + new_retransmit_list->next = cur_retransmit_list; + cur_retransmit_list = cur_retransmit_list->next; + new_retransmit_list = new_retransmit_list->next; + new_retransmit_list->next = NULL; + /* go process the next pdu, still for the current nack */ + goto process_next_pdu; + } + + /* if current segment SN > current NACK, we can't classify it yet */ + if (sn_compare_tx(entity, cur_retransmit_list->sdu->sn, cur_nack_sn) > 0 + || (cur_retransmit_list->sdu->sn == cur_nack_sn + && cur_retransmit_list->so > cur_so_start)) + goto done_nack; + + /* if current segment is acked, free it, indicate successful delivery + * if fully acked + */ + if (sn_compare_tx(entity, cur_retransmit_list->sdu->sn, ack_sn) < 0) { + nr_rlc_sdu_segment_t *cur = cur_retransmit_list; + int upper_layer_id = cur->sdu->upper_layer_id; + int sdu_size = cur->sdu->size; + cur_retransmit_list = cur_retransmit_list->next; + /* update buffer status */ + entity->common.bstatus.retx_size -= compute_pdu_header_size(entity, cur) + + cur->size; + if (nr_rlc_free_sdu_segment(cur)) { + entity->tx_size -= sdu_size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (nr_rlc_entity_t *)entity, upper_layer_id); + } + goto process_next_pdu; + } + + /* current segment SN >= ack_sn + * if the wait list is empty, then put the remaining retransmit list at + * the end of the new retransmit list (just a speedup) + * if not, put only this segment + */ + if (cur_wait_list == NULL) { + new_retransmit_list->next = cur_retransmit_list; + cur_retransmit_list = NULL; + goto lists_over; + } + new_retransmit_list->next = cur_retransmit_list; + cur_retransmit_list = cur_retransmit_list->next; + new_retransmit_list = new_retransmit_list->next; + new_retransmit_list->next = NULL; + goto process_next_pdu; + +done_nack: + prev_nack_sn = cur_nack_sn; + prev_so_start = cur_so_start; + prev_so_end = cur_so_end; + } /* for (i = 0; i < range; i++) */ + +lists_over: + /* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' - check NACK case (ACK done above) + */ + if (sn_compare_tx(entity, nack_sn, entity->poll_sn) <= 0 && + sn_compare_tx(entity, entity->poll_sn, (nack_sn + range) % entity->sn_modulus) < 0) + entity->t_poll_retransmit_start = 0; + } /* while (e1) */ + +nacks_done: + /* nacks done, finish with ack */ + /* we may report successful delivery out of order, if it's a problem + * then we can have a single loop and deal with the smallest sn of + * the current head of wait list and the current head of retransmit list. + * (It's simpler to process those two lists the one after the other.) */ - while (cur != NULL && cur->sdu->sn == entity->tx_next_ack && - sdu_segment_in_ack_list_full(cur)) { - entity->tx_size -= cur->sdu->size; - sn = cur->sdu->sn; - entity->common.sdu_successful_delivery( - entity->common.sdu_successful_delivery_data, - (nr_rlc_entity_t *)entity, cur->sdu->upper_layer_id); - while (cur != NULL && cur->sdu->sn == sn) { - nr_rlc_sdu_segment_t *s = cur; - cur = cur->next; - nr_rlc_free_sdu_segment(s); + /* deal with wait list */ + while (cur_wait_list != NULL + && sn_compare_tx(entity, cur_wait_list->sdu->sn, ack_sn) < 0) { + /* current segment is acked, free it, indicate successful delivery + * if fully acked + */ + nr_rlc_sdu_segment_t *cur = cur_wait_list; + int upper_layer_id = cur->sdu->upper_layer_id; + int sdu_size = cur->sdu->size; + prev_wait_list->next = cur_wait_list->next; + if (cur_wait_list == entity->wait_end) + end_wait_list = prev_wait_list; + cur_wait_list = cur_wait_list->next; + if (nr_rlc_free_sdu_segment(cur)) { + entity->tx_size -= sdu_size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (nr_rlc_entity_t *)entity, upper_layer_id); } - entity->ack_list = cur; - entity->tx_next_ack = (entity->tx_next_ack + 1) % entity->sn_modulus; } + /* deal with retransmit list */ + while (cur_retransmit_list != NULL + && sn_compare_tx(entity, cur_retransmit_list->sdu->sn, ack_sn) < 0) { + /* current segment is acked, free it, indicate successful delivery + * if fully acked + */ + nr_rlc_sdu_segment_t *cur = cur_retransmit_list; + int upper_layer_id = cur->sdu->upper_layer_id; + int sdu_size = cur->sdu->size; + cur_retransmit_list = cur_retransmit_list->next; + /* update buffer status */ + entity->common.bstatus.retx_size -= compute_pdu_header_size(entity, cur) + + cur->size; + if (nr_rlc_free_sdu_segment(cur)) { + entity->tx_size -= sdu_size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (nr_rlc_entity_t *)entity, upper_layer_id); + } + } + + new_retransmit_list->next = cur_retransmit_list; + + entity->wait_list = head_wait_list.next; + entity->retransmit_list = head_retransmit_list.next; + + if (end_wait_list != NULL) { + if (end_wait_list == &head_wait_list) + entity->wait_end = NULL; + else + entity->wait_end = end_wait_list; + } + + /* update tx_next_ack */ + /* 38.322 5.2.3.1.1 says "set TX_Next_Ack equal to the SN of the RLC SDU + * with the smallest SN, whose SN falls within the range + * TX_Next_Ack <= SN <= TX_Next and for which a positive acknowledgment + * has not been received yet. + */ + /* let's start from highest possible value and go down as needed */ + tx_next_ack = entity->tx_next; + if (entity->wait_list != NULL + && sn_compare_tx(entity, entity->wait_list->sdu->sn, tx_next_ack) < 0) + tx_next_ack = entity->wait_list->sdu->sn; + if (entity->retransmit_list != NULL + && sn_compare_tx(entity, entity->retransmit_list->sdu->sn, tx_next_ack) < 0) + tx_next_ack = entity->retransmit_list->sdu->sn; + if (sn_compare_tx(entity, ack_sn, tx_next_ack) < 0) + tx_next_ack = ack_sn; + entity->tx_next_ack = tx_next_ack; + + return; + +err: + LOG_E(RLC, "%s:%d:%s: error decoding PDU, NR RLC entity in inconsistent state\n", + __FILE__, __LINE__, __FUNCTION__); + +#undef R } void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, @@ -540,7 +674,6 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, #define R(d) do { if (nr_rlc_pdu_decoder_in_error(&d)) goto err; } while (0) nr_rlc_entity_am_t *entity = (nr_rlc_entity_am_t *)_entity; nr_rlc_pdu_decoder_t decoder; - nr_rlc_pdu_decoder_t control_decoder; nr_rlc_pdu_t *pdu; int dc; int p = 0; @@ -551,23 +684,11 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, int is_first; int is_last; - int cpt; - int e1; - int e2; - int e3; - int ack_sn; - int nack_sn; - int so_start; - int so_end; - int range; - int control_e1; - int control_e2; - int control_e3; - unsigned char sn_set[32768]; /* used to dec retx_count only once per sdu */ - nr_rlc_pdu_decoder_init(&decoder, buffer, size); dc = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - if (dc == 0) goto control; + + if (dc == 0) + return process_control_pdu(entity, buffer, size); /* data PDU */ p = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); @@ -596,20 +717,20 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, /* dicard PDU if no data */ if (data_size <= 0) { - LOG_W(RLC, "%s:%d:%s: warning: discard PDU, no data\n", + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, no data\n", __FILE__, __LINE__, __FUNCTION__); goto discard; } /* dicard PDU if rx buffer is full */ if (entity->rx_size + data_size > entity->rx_maxsize) { - LOG_W(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", __FILE__, __LINE__, __FUNCTION__); goto discard; } if (!sn_in_recv_window(entity, sn)) { - LOG_W(RLC, "%s:%d:%s: warning: discard PDU, sn out of window (sn %d rx_next %d)\n", + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, sn out of window (sn %d rx_next %d)\n", __FILE__, __LINE__, __FUNCTION__, sn, entity->rx_next); goto discard; @@ -617,7 +738,7 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, /* discard segment if all the bytes of the segment are already there */ if (segment_already_received(entity, sn, so, data_size)) { - LOG_W(RLC, "%s:%d:%s: warning: discard PDU, already received\n", + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, already received\n", __FILE__, __LINE__, __FUNCTION__); goto discard; } @@ -650,118 +771,6 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, return; -control: - cpt = nr_rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); - if (cpt != 0) { - LOG_W(RLC, "%s:%d:%s: warning: discard PDU, CPT not 0 (%d)\n", - __FILE__, __LINE__, __FUNCTION__, cpt); - goto discard; - } - ack_sn = nr_rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); - e1 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - /* r bits */ - if (entity->sn_field_length == 18) { - nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - } else { - nr_rlc_pdu_decoder_get_bits(&decoder, 7); R(decoder); - } - - /* let's try to parse the control PDU once to check consistency */ - control_decoder = decoder; - control_e1 = e1; - while (control_e1) { - nack_sn = nr_rlc_pdu_decoder_get_bits(&control_decoder, entity->sn_field_length); R(control_decoder); - control_e1 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); - control_e2 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); - control_e3 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); - /* r bits */ - if (entity->sn_field_length == 18) { - nr_rlc_pdu_decoder_get_bits(&control_decoder, 3); R(control_decoder); - } else { - nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); - } - /* check range and so_start/so_end consistency */ - if (control_e2) { - so_start = nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder); - so_end = nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder); - } else { - so_start = 0; - so_end = 0xffff; - } - if (control_e3) { - range = nr_rlc_pdu_decoder_get_bits(&control_decoder, 8); R(control_decoder); - } else { - range = 1; - } - if (range < 1) { - LOG_E(RLC, "%s:%d:%s: error, bad 'range' in RLC NACK (sn %d)\n", - __FILE__, __LINE__, __FUNCTION__, nack_sn); - goto err; - } - /* so_start can be > so_end if more than one range; they don't refer - * to the same PDU then - */ - if (range == 1 && so_end < so_start) { - LOG_E(RLC, "%s:%d:%s: error, bad so start/end (sn %d)\n", - __FILE__, __LINE__, __FUNCTION__, nack_sn); - goto err; - } - } - - /* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is - * received for the SN 'poll_sn' - check ACK case (NACK done below) - */ - if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0) - entity->t_poll_retransmit_start = 0; - - /* at this point, accept the PDU even if the actual values - * may be incorrect (eg. if so_start > so_end) - */ - process_received_ack(entity, ack_sn); - - if (e1) - memset(sn_set, 0, 32768); - - while (e1) { - nack_sn = nr_rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); - e1 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - e2 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - e3 = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - /* r bits */ - if (entity->sn_field_length == 18) { - nr_rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); - } else { - nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); - } - if (e2) { - so_start = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder); - so_end = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder); - } else { - so_start = 0; - so_end = 0xffff; - } - if (e3) { - range = nr_rlc_pdu_decoder_get_bits(&decoder, 8); R(decoder); - } else { - range = 1; - } - /* special value 0xffff indicates 'all bytes to the end' */ - if (so_end == 0xffff) - so_end = -1; - process_received_nack(entity, nack_sn, so_start, so_end, range, sn_set); - - /* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is - * received for the SN 'poll_sn' - check NACK case (ACK done above) - */ - if (sn_compare_tx(entity, nack_sn, entity->poll_sn) <= 0 && - sn_compare_tx(entity, entity->poll_sn, (nack_sn + range) % entity->sn_modulus) < 0) - entity->t_poll_retransmit_start = 0; - } - - finalize_ack_nack_processing(entity); - - return; - err: LOG_W(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__); goto discard; @@ -1225,7 +1234,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity, static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size) { int ack_sn = entity->rx_next; - missing_data_t m; + missing_data_t m; nr_rlc_pdu_t *cur; int nack_count = 0; nr_rlc_pdu_encoder_t encoder; @@ -1427,8 +1436,6 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer, return 0; entity->retransmit_list = entity->retransmit_list->next; - if (entity->retransmit_list == NULL) - entity->retransmit_end = NULL; sdu->next = NULL; @@ -1444,15 +1451,24 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer, /* put the second SDU back at the head of the retransmit list */ next_sdu->next = entity->retransmit_list; entity->retransmit_list = next_sdu; - if (entity->retransmit_end == NULL) - entity->retransmit_end = entity->retransmit_list; /* update buffer status */ entity->common.bstatus.retx_size += compute_pdu_header_size(entity, next_sdu) + next_sdu->size; } /* put SDU/SDU segment in the wait list */ - nr_rlc_sdu_segment_list_append(&entity->wait_list, &entity->wait_end, sdu); + /* speedup: check end of wait list, maybe the new sdu comes after */ + if (entity->wait_end == NULL + || sn_compare_tx(entity, sdu->sdu->sn, entity->wait_end->sdu->sn) > 0 + || (sn_compare_tx(entity, sdu->sdu->sn, entity->wait_end->sdu->sn) == 0 + && sdu->so > entity->wait_end->so)) + nr_rlc_sdu_segment_list_append(&entity->wait_list, &entity->wait_end, sdu); + else { + entity->wait_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, + entity->wait_list, sdu); + if (entity->wait_list->next == NULL) + entity->wait_end = entity->wait_list; + } p = check_poll_after_pdu_assembly(entity); @@ -1519,7 +1535,18 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size) entity->tx_next = (entity->tx_next + 1) % entity->sn_modulus; /* put SDU/SDU segment in the wait list */ - nr_rlc_sdu_segment_list_append(&entity->wait_list, &entity->wait_end, sdu); + /* speedup: check end of wait list, probably the new sdu comes after */ + if (entity->wait_end == NULL + || sn_compare_tx(entity, sdu->sdu->sn, entity->wait_end->sdu->sn) > 0 + || (sn_compare_tx(entity, sdu->sdu->sn, entity->wait_end->sdu->sn) == 0 + && sdu->so > entity->wait_end->so)) + nr_rlc_sdu_segment_list_append(&entity->wait_list, &entity->wait_end, sdu); + else { + entity->wait_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, + entity->wait_list, sdu); + if (entity->wait_list->next == NULL) + entity->wait_end = entity->wait_list; + } /* polling actions for a new PDU */ entity->pdu_without_poll++; @@ -1629,11 +1656,7 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity) { - nr_rlc_sdu_segment_t head; nr_rlc_sdu_segment_t *cur; - nr_rlc_sdu_segment_t *prev; - int sn; - int old_retx_count; /* 38.322 5.3.3.4 */ /* did t_poll_retransmit expire? */ @@ -1659,74 +1682,58 @@ static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity) */ entity->force_poll = 1; - LOG_W(RLC, "%s:%d:%s: warning: t_poll_retransmit expired\n", + LOG_D(RLC, "%s:%d:%s: warning: t_poll_retransmit expired\n", __FILE__, __LINE__, __FUNCTION__); /* do we meet conditions of 38.322 5.3.3.4? */ if (!check_poll_after_pdu_assembly(entity)) return; - /* search wait list for SDU with highest SN */ - /* this code may be incorrect: in LTE we had to look for PDU - * with SN = VT(S) - 1, but for NR the specs say "highest SN among the - * ones submitted to lower layers" not 'tx_next - 1'. So we should look - * for the highest SN in the wait list. But that's no big deal. If the - * program runs this code, then the connection is in a bad state and we - * can retransmit whatever we want. At some point we will receive a status - * report and retransmit what we really have to. Actually we could just - * retransmit the head of wait list (the specs have this 'or'). - * (Actually, maybe this interpretation is not correct and what the code - * does is correct. The specs are confusing.) + /* retransmit the head of wait list, this is the case + * "consider any RLC SDU which has not been positively acknowledged for + * retransmission" of 36.322 5.3.3.4. + * We don't search for the highest SN, it's simpler to just take the head + * of wait list. This can be changed if needed. */ - sn = (entity->tx_next - 1 + entity->sn_modulus) % entity->sn_modulus; - - head.next = entity->wait_list; cur = entity->wait_list; - prev = &head; - - while (cur != NULL) { - if (cur->sdu->sn == sn) - break; - prev = cur; - cur = cur->next; - } - - /* SDU with highest SN not found? take the head of wait list */ - if (cur == NULL) { - cur = entity->wait_list; - prev = &head; - sn = cur->sdu->sn; - } /* todo: do we need to for check cur == NULL? * It seems that no, the wait list should not be empty here, but not sure. */ - old_retx_count = cur->sdu->retx_count; + entity->wait_list = cur->next; + if (entity->wait_list == NULL) + entity->wait_end = NULL; - /* 38.322 says "SDU", not "SDU segment", so let's retransmit all - * SDU segments with this SN + /* 38.322 says "SDU", not "SDU segment", but let's retransmit only + * the 'cur' SDU segment. To be changed if needed. (Maybe we have + * to retransmit all SDU segments with the same SN that are in the + * wait list.) */ - /* todo: maybe we could simply retransmit the current SDU segment, - * so that we don't have to run through the full wait list. + + /* increase retx count. Don't care about segmentation, so maybe we + * increase too much. */ - while (cur != NULL) { - if (cur->sdu->sn == sn) { - prev->next = cur->next; - cur->next = NULL; - /* put in retransmit list */ - consider_retransmission(entity, cur, - old_retx_count == cur->sdu->retx_count); - } else { - prev = cur; - } - cur = prev->next; - } - entity->wait_list = head.next; - /* reset wait_end (todo: optimize?) */ - entity->wait_end = entity->wait_list; - while (entity->wait_end != NULL && entity->wait_end->next != NULL) - entity->wait_end = entity->wait_end->next; + cur->sdu->retx_count++; + /* report max RETX reached for all retx_count >= max_retx_threshold + * (specs say to report if retx_count == max_retx_threshold). + * Upper layers should react (radio link failure), so no big deal. + * We deal with segmentation by requiring + * retx_count >= max_retx_threshold * number of segments. + * We may report max RETX reached too late/early. To be refined if + * this is a problem. + */ + if (cur->sdu->retx_count + >= entity->max_retx_threshold * cur->sdu->ref_count) + entity->common.max_retx_reached(entity->common.max_retx_reached_data, + (nr_rlc_entity_t *)entity); + /* update buffer status */ + entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur) + + cur->size; + + /* put in retransmit list */ + entity->retransmit_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, + entity->retransmit_list, cur); } static void check_t_reassembly(nr_rlc_entity_am_t *entity) @@ -1815,6 +1822,7 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id) entity->common.bstatus.tx_size -= compute_pdu_header_size(entity, cur) + cur->size; + entity->tx_size -= cur->sdu->size; nr_rlc_free_sdu_segment(cur); } @@ -1857,7 +1865,6 @@ static void clear_entity(nr_rlc_entity_am_t *entity) nr_rlc_free_sdu_segment_list(entity->tx_list); nr_rlc_free_sdu_segment_list(entity->wait_list); nr_rlc_free_sdu_segment_list(entity->retransmit_list); - nr_rlc_free_sdu_segment_list(entity->ack_list); entity->tx_list = NULL; entity->tx_end = NULL; @@ -1867,9 +1874,6 @@ static void clear_entity(nr_rlc_entity_am_t *entity) entity->wait_end = NULL; entity->retransmit_list = NULL; - entity->retransmit_end = NULL; - - entity->ack_list = NULL; entity->common.bstatus.tx_size = 0; entity->common.bstatus.retx_size = 0; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h index 453fe87026..57ae1a3485 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h @@ -84,9 +84,6 @@ typedef struct { nr_rlc_sdu_segment_t *wait_end; nr_rlc_sdu_segment_t *retransmit_list; - nr_rlc_sdu_segment_t *retransmit_end; - - nr_rlc_sdu_segment_t *ack_list; } nr_rlc_entity_am_t; void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *entity, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c index ef0d52558a..ef64389ac5 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c @@ -58,14 +58,19 @@ oom: exit(1); } -void nr_rlc_free_sdu_segment(nr_rlc_sdu_segment_t *sdu) +int nr_rlc_free_sdu_segment(nr_rlc_sdu_segment_t *sdu) { - sdu->sdu->ref_count--; - if (sdu->sdu->ref_count == 0) { + int ret = 0; + + sdu->sdu->free_count++; + if (sdu->sdu->free_count == sdu->sdu->ref_count) { free(sdu->sdu->data); free(sdu->sdu); + ret = 1; } free(sdu); + + return ret; } void nr_rlc_sdu_segment_list_append(nr_rlc_sdu_segment_t **list, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h index f4585fb7d6..20cc90f185 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h @@ -30,6 +30,10 @@ typedef struct nr_rlc_sdu_t { int retx_count; int ref_count; /* incremented each time the SDU is segmented */ + int free_count; /* incremented each time a segment is freed + * when it equals ref_count we can free the SDU + * completely + */ } nr_rlc_sdu_t; typedef struct nr_rlc_sdu_segment_t { @@ -44,7 +48,8 @@ typedef struct nr_rlc_sdu_segment_t { nr_rlc_sdu_segment_t *nr_rlc_new_sdu( char *buffer, int size, int upper_layer_id); -void nr_rlc_free_sdu_segment(nr_rlc_sdu_segment_t *sdu); +/* return 1 if the SDU has been freed too, 0 if not (more segments to free) */ +int nr_rlc_free_sdu_segment(nr_rlc_sdu_segment_t *sdu); void nr_rlc_sdu_segment_list_append(nr_rlc_sdu_segment_t **list, nr_rlc_sdu_segment_t **end, nr_rlc_sdu_segment_t *sdu); diff --git a/openair2/LAYER2/nr_rlc/tests/test14.txt.gz b/openair2/LAYER2/nr_rlc/tests/test14.txt.gz index 53616dae3d10b71375cea41ca9061d4304f64dcf..45e54651eb317c3b7695cfcab7428fe43172227b 100644 GIT binary patch delta 727 zcmV;|0x12M2A>9hABzYGOnK#D0t0kqb96B@E_8Tw0Ns{LYhyM4NCCm^MOEKZ=bSpax9>mP-mu=3)#kg~ z{rThj8|)3M(LUX+`va@j9?Uh<1qmfF$t3~1yeB%vosFO z#2T!{I;>z7>#+eFu?d^81zWKV+pz;XaRz5`4ktLpd0fCnT*75s!Bt$tb=<&B#31&! zL;SywKgOzT#@(NN`vhKg;G5awH34cl-io5)8o-96^ro zpHsnJ_7p$=^5cGtJ|6BrjTIk$`uLMT0at$vP`7iA)!mX%o9%j^RLk>jKZUUQ`|)I! zIsZ8yU2wvJ@)Tmb-w|Qw9P6%ww$qNiXy`iu^vJPt=-3>{k(|hxT*#H&$eldMlVT{A z;wVBZySmsfn7Yg<7eN+Npy&cMfQl=4gLH zQ<|p*T0Ed$-|AR>on!U9W92$%JMGxZhwk61xPQ6g`}*+g3(d1H+*#%={g3gIP9hHf zB3?d{PR8rfxRclNS6Q>(wl>!5xqW!}{G|Tq?@rXaSJulb>i-AdiJFg6Qx8+KC0eEx zTBS8wrw!Vq8@i=Cy3m#G>46^UiJpJygt< zMrRDhWE!SrI;Jp{>6w8UnTeT?2RNsLUiKJ|DVDz#W0#M8XO(ASA-o{R%-L87Cu3pP zxT8y7xVC4Yo=z|?M>kyg;_oR>{y$RwjmE1a;Pl2_0rqh2kKgKnX5n#7%(Dw?@)b>e JEYZ;s0009vZy5jp delta 720 zcmV;>0x$ia2ABqaABzYG$u*{70t0kqb96B@E_8Tw0Ns{5ZyZMugmeFjFSHY5X1eFa zP>|rviKxghhZ@~X5=8Fzp5?Gt#}fp2Dy-&}qd?nniDsDd~|5Jfx^kccECBL%5QLpm~$i5k?R z4i!{Uj|MbCq6y7tK`YwOjt+D#=i@EjEsWt6@9_a2@d=;t1z+(E-|-8WNiYOUa0EHR ze@+E^*zjQWeLUQM9xL9z{qU1O0at%CP`7iA)!mX%o9%j^RLlEr--WRG>v3h4 zKL1%C9dN>e@)Tmb=ZLU#j&;{T+iAyMH1wSSdgNF+bZidfNKWKTF62sXuXU`x%&~gjv2q=>op$WyL-(&$+<(8~`}*+gh344{cb0k0{>OMpClQB# z5idVUC*w8!FaFCkAElHYrc_I`Oe?fXYqU-qv`IH~OLugkE8WurJ<=0B(+j=Q8@(^H zK%Wf5unfl#hB7=OFd`!{GNUjmqcMLvV=yMuFfG$Dg{e%>49v((%zWIyIUV$}+jvZk z{H@ryeC#``JTr#jJ95LE9m8;P49{GBIsv>Kop9xYyr(ev|489CHeMwGrzhwNu!nOW zPOAr+E%mz|4S$w3>uqaey`I~Lhc8bQjQ;b9di%n9_riL4VZA?BT%gc&;HC?*=-Ux2N2b{wRPH`S*xPXhegv+>s>u^18z)gh>HzE!ZL=le| z5|D@_BqIgskRBP3iZo=W>c_jtnx ze8eYw#ut2t@9_h^;v0U%9444z9y2Up5ldLc3f5sgHeeNN*f{kk2tf&+V1z)3gha@M zLg)xRVIWk(1ZE^Uq7aqn4-(LQ0?~+p7>S9PiG|n^d*VQ>#6}!RjwB={d6JO=DUuQ? zlM1OL^`wDRNsTm;9a+dq_GBXmawI2mCKqx??#TnWk{fxXIEqk|;weT6zY_S=KDT9e z-7db=^%lKt&`*`_=XyFL?cvjV@kyTXb$9U1=6k&V{Bid3#4g;!XUEygmi=FtHymfL zPi)~meDMJLw!?SJ{&CJfKiM>|?dtNTEjfLAz6;&{nH)eRcJ1CuOUz_X^}+rFTP29vb2E|M*M~ sWUv0;muI7`KBVol{*!mmkK|+cZ5A^}_s6#07RbSZA0L&&0<;ML09iH+!vFvP literal 546 zcmV+-0^R)|iwFqSHKt(#19W9`bTKt9ba-?C&6P`QlR*@Q_x_4!sT-MdnOl}(ap$J( zN~C<3`J_-plBS}+-Xu+=(U?%dS{Q~|%o(2d%=^w85xL?J5Ch)#^eM9joOti+Dk z69?i*T)|AFKoXLY?5F_U7m%D3Nr{w6g;Yr$sV5Djk<>^NIgo{{WFtE{k`pmKl}&G&f!*=hCi#4g<9^V8~OtNt&{8&9j(C${h& zUpk_`?fCB1KhF7=XPd*vc5{8#=A6I1+=ceJXLd_|pe?q0@z>+w_Vs-pYNI?TXxqgq zp!fY;&#R#8z8mFVg>l0vf4Y(9|BtyIiPHFgACgUP^-sNh)?e%n{e<0z-|k|qG4Qop kuviX5TP&vK&CR!63)=YlP=P$QK#vyu0JKzLn6wE10El1~J^%m! From bd7f837f18aa2b30b28bdeff9f1f7433ac226fcd Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 13:23:17 +0100 Subject: [PATCH 085/226] Fix after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 3 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 +- openair2/RRC/NR/rrc_gNB.c | 60 +++++++++++++++++-- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index ecc2ef0cff..b82a2b0925 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -349,6 +349,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, // This updates the timers running at MAC layer nr_mac_update_timers(module_idP, frame, slot); + // This schedules the BWP switching + schedule_nr_bwp_switch(module_idP, frame, slot); + // This schedules MIB schedule_nr_mib(module_idP, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index da3556e675..a75b2b6265 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1992,8 +1992,10 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, sib1); + // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - sched_ctrl->rrc_processing_timer = (10 << genericParameters->subcarrierSpacing); // RRCSetup 10 ms + uint32_t delay_ms = bwpList ? 16 : 10; + sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7cb1af60dc..93973d1ca6 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -741,6 +741,12 @@ rrc_gNB_generate_defaultRRCReconfiguration( LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + rrc_mac_config_req_gNB(ctxt_pP->module_id, 0, rrc->configuration.pdsch_AntennaPorts, @@ -753,7 +759,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + delay_ms); /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1021,6 +1027,12 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + rrc_mac_config_req_gNB(ctxt_pP->module_id, 0, rrc->configuration.pdsch_AntennaPorts, @@ -1033,7 +1045,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + delay_ms); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1208,6 +1220,12 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + rrc_mac_config_req_gNB(ctxt_pP->module_id, 0, RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, @@ -1220,7 +1238,7 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + delay_ms); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { @@ -1326,6 +1344,12 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + rrc_mac_config_req_gNB(ctxt_pP->module_id, 0, RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, @@ -1338,7 +1362,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + delay_ms); /* Free all NAS PDUs */ if (nas_length > 0) { @@ -1891,6 +1915,12 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + rrc_mac_config_req_gNB(ctxt_pP->module_id, 0, RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, @@ -1903,7 +1933,7 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + delay_ms); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1978,7 +2008,25 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP NULL, masterCellGroup); - enable_nr_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP, TX_SL_AHEAD_DELAY + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS); + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_PROCESSING_DELAY_MS + NR_RRC_BWP_SWITCH_DELAY_MS : NR_RRC_PROCESSING_DELAY_MS; + + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + delay_ms); nr_rrc_data_req(ctxt_pP, DCCH, From 5c176c454aa48ea601e360707bbee624eac1ab19 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 16:34:10 +0100 Subject: [PATCH 086/226] Fix mcs table update during RRCReconfiguration --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 -- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 ++--- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 23 +++++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 4f19a313ae..06f1433300 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -673,8 +673,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Modified UE_id %d/%x with CellGroup\n",UE_id,rnti); process_CellGroup(CellGroup,&UE_info->UE_sched_ctrl[UE_id]); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - sched_ctrl->update_pdsch_ps = true; - sched_ctrl->update_pusch_ps = true; const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; if (get_softmodem_params()->sa) { // add all available DL HARQ processes for this UE in SA diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index f72ccaf6e5..0ad56751d3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -589,7 +589,7 @@ bool allocate_dl_retransmission(module_id_t module_id, } /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ - if (ps->time_domain_allocation != tda || sched_ctrl->update_pdsch_ps) { + if (ps->time_domain_allocation != tda) { nr_set_pdsch_semi_static(sib1, scc, cg, @@ -599,7 +599,6 @@ bool allocate_dl_retransmission(module_id_t module_id, ps->nrOfLayers, sched_ctrl, ps); - sched_ctrl->update_pdsch_ps = false; } } else { /* the retransmission will use a different time domain allocation, check @@ -914,7 +913,6 @@ void pf_dl(module_id_t module_id, layers[UE_id], sched_ctrl, ps); - sched_ctrl->update_pdsch_ps = false; } const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); @@ -1067,6 +1065,8 @@ void nr_mac_update_timers(module_id_t module_id, sched_ctrl->rrc_processing_timer--; if (sched_ctrl->rrc_processing_timer == 0) { LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); + sched_ctrl->update_pdsch_ps = true; + sched_ctrl->update_pusch_ps = true; } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 6f17556c91..e901d0d669 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -579,16 +579,21 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, bwpd = (NR_BWP_DownlinkDedicated_t*)bwpd0; } - if (bwpd && - bwpd->pdsch_Config && - bwpd->pdsch_Config->choice.setup && - bwpd->pdsch_Config->choice.setup->mcs_Table) { - if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) - ps->mcsTableIdx = 1; - else - ps->mcsTableIdx = 2; + if (sched_ctrl->update_pdsch_ps == true) { + if (bwpd && + bwpd->pdsch_Config && + bwpd->pdsch_Config->choice.setup && + bwpd->pdsch_Config->choice.setup->mcs_Table) { + if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) { + ps->mcsTableIdx = 1; + } else { + ps->mcsTableIdx = 2; + } + } else { + ps->mcsTableIdx = 0; + } + sched_ctrl->update_pdsch_ps = false; } - else ps->mcsTableIdx = 0; LOG_D(NR_MAC,"MCS Table Index: %d\n",ps->mcsTableIdx); NR_PDSCH_Config_t *pdsch_Config; From 7508205f907c3ece049e2584830bfb06be73fdc4 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 16:39:49 +0100 Subject: [PATCH 087/226] Move nr_mac_update_timers function to gNB_scheduler_primitives --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 18 ------------------ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 0ad56751d3..98ec1ae659 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1054,24 +1054,6 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(module_id_t module_id, int CC_id) return nr_fr1_dlsch_preprocessor; } -void nr_mac_update_timers(module_id_t module_id, - frame_t frame, - sub_frame_t slot) { - NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; - const NR_list_t *UE_list = &UE_info->list; - for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->rrc_processing_timer > 0) { - sched_ctrl->rrc_processing_timer--; - if (sched_ctrl->rrc_processing_timer == 0) { - LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); - sched_ctrl->update_pdsch_ps = true; - sched_ctrl->update_pusch_ps = true; - } - } - } -} - void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, sub_frame_t slot) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index e901d0d669..1ae83b0ffd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2796,6 +2796,23 @@ void nr_csirs_scheduling(int Mod_idP, } } +void nr_mac_update_timers(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + const NR_list_t *UE_list = &UE_info->list; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer--; + if (sched_ctrl->rrc_processing_timer == 0) { + LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); + sched_ctrl->update_pdsch_ps = true; + sched_ctrl->update_pusch_ps = true; + } + } + } +} /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg, nfapi_nr_coreset_t *coreset, From 72f40e6fb1dee33ecfdab78adcd753c5492a4e5e Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 17:04:05 +0100 Subject: [PATCH 088/226] Add definition for some rrc processing delays --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 4 +++- openair2/RRC/NR/rrc_gNB.c | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index c76e6d238a..32e1a238f0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1952,7 +1952,7 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, sib1); // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - sched_ctrl->rrc_processing_timer = (10 << genericParameters->subcarrierSpacing); // RRCSetup 10 ms + sched_ctrl->rrc_processing_timer = (NR_RRC_SETUP_DELAY_MS << genericParameters->subcarrierSpacing); // RRCSetup 10 ms } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 268168750c..5cc3157bce 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -97,7 +97,9 @@ typedef struct nr_uid_linear_allocator_s { #define PROTOCOL_NR_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs -#define NR_RRC_PROCESSING_DELAY_MS 10 +#define NR_RRC_SETUP_DELAY_MS 10 +#define NR_RRC_RECONFIGURATION_DELAY_MS 10 +#define NR_RRC_BWP_SWITCHING_DELAY_MS 6 #define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! #define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a7e6e49052..0670765d1b 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -744,7 +744,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + NR_RRC_RECONFIGURATION_DELAY_MS); /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1024,7 +1024,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + NR_RRC_RECONFIGURATION_DELAY_MS); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1211,7 +1211,7 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + NR_RRC_RECONFIGURATION_DELAY_MS); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { @@ -1329,7 +1329,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + NR_RRC_RECONFIGURATION_DELAY_MS); /* Free all NAS PDUs */ if (nas_length > 0) { @@ -1894,7 +1894,7 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( 0, ue_context_pP->ue_context.rnti, NULL, - NR_RRC_PROCESSING_DELAY_MS); + NR_RRC_RECONFIGURATION_DELAY_MS); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { From 55f1a6b4daed84fd58f044d001672af9d73f6951 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 17:28:48 +0100 Subject: [PATCH 089/226] Stop the scheduling of CSI-RS, of CSI measurement report reception on PUCCH2 and of reception of SRS --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 5 +++++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1ae83b0ffd..d7478474b1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2609,6 +2609,11 @@ void nr_csirs_scheduling(int Mod_idP, for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + + if (sched_ctrl->rrc_processing_timer > 0) { + continue; + } + NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index bf2af3b388..8680cc25d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -125,7 +125,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.slot = -1; sched_ctrl->sched_srs.srs_scheduled = false; - if(!UE_info->Msg4_ACKed[UE_id]) { + if(!UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index e21d1e50f7..e2d9f1035c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -702,7 +702,9 @@ void nr_csi_meas_reporting(int Mod_idP, for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { const NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; + if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { + continue; + } if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; const NR_CSI_MeasConfig_t *csi_measconfig = CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; From 33663e68b093ffdb28ff5e31f9dd3f360eb9dbf7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 19 Apr 2022 18:37:14 +0200 Subject: [PATCH 090/226] rename frame_type --- common/utils/nr/nr_common.c | 4 ++-- common/utils/nr/nr_common.h | 2 +- openair1/PHY/LTE_TRANSPORT/prach.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach_common.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach_extern.h | 2 +- openair1/PHY/LTE_TRANSPORT/transport_common_proto.h | 4 ++-- openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c | 10 +++++----- openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c | 2 +- openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h | 4 ++-- openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h | 4 ++-- openair1/PHY/defs_common.h | 4 ++-- openair1/PHY/defs_nr_common.h | 2 +- openair1/SCHED/phy_procedures_lte_common.c | 2 +- openair1/SCHED/sched_common.h | 2 +- openair1/SCHED/sched_eNB.h | 2 +- openair1/SCHED_UE/phy_procedures_lte_ue.c | 2 +- openair1/SCHED_UE/sched_UE.h | 2 +- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 2 +- openair2/COMMON/m2ap_messages_types.h | 4 ++-- openair2/COMMON/m3ap_messages_types.h | 2 +- openair2/COMMON/phy_messages_types.h | 2 +- openair2/COMMON/rrc_messages_types.h | 4 ++-- openair2/COMMON/x2ap_messages_types.h | 2 +- openair2/ENB_APP/RRC_config_tools.h | 2 +- openair2/ENB_APP/flexran_agent_ran_api.c | 2 +- openair2/ENB_APP/flexran_agent_ran_api.h | 2 +- openair2/GNB_APP/gnb_config.c | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 2 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 2 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- openair2/M2AP/m2ap_MCE_defs.h | 2 +- openair2/M2AP/m2ap_eNB_defs.h | 2 +- openair2/RRC/LTE/rrc_eNB_S1AP.c | 2 +- openair2/RRC/NR/nr_rrc_config.c | 4 ++-- openair2/UTIL/OCG/OCG.h | 2 +- openair2/X2AP/x2ap_eNB_defs.h | 2 +- openair3/M3AP/m3ap_MCE_defs.h | 2 +- openair3/M3AP/m3ap_MME_defs.h | 2 +- targets/RT/USER/lte-ue.c | 2 +- 45 files changed, 59 insertions(+), 59 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 49743b3bdc..0aeeaf3afd 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -336,9 +336,9 @@ int get_dmrs_port(int nl, uint16_t dmrs_ports) { return p; } -lte_frame_type_t get_frame_type(uint16_t current_band, uint8_t scs_index) +frame_type_t get_frame_type(uint16_t current_band, uint8_t scs_index) { - lte_frame_type_t current_type; + frame_type_t current_type; int32_t delta_duplex = get_delta_duplex(current_band, scs_index); if (delta_duplex == 0) diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 0150cf59f8..a09532a565 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -63,7 +63,7 @@ void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset); uint16_t config_bandwidth(int mu, int nb_rb, int nr_band); int get_nr_table_idx(int nr_bandP, uint8_t scs_index); int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index); -lte_frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); +frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex); int NRRIV2BW(int locationAndBandwidth,int N_RB); int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB); diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index eb46a8d663..91c419ebe3 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -56,7 +56,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, uint8_t ce_level ) { int i; - lte_frame_type_t frame_type; + frame_type_t frame_type; uint16_t rootSequenceIndex; uint8_t prach_ConfigIndex; uint8_t Ncs_config; diff --git a/openair1/PHY/LTE_TRANSPORT/prach_common.c b/openair1/PHY/LTE_TRANSPORT/prach_common.c index e366e8edbc..f3409a90e3 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach_common.c +++ b/openair1/PHY/LTE_TRANSPORT/prach_common.c @@ -399,7 +399,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint32_t X_u[64][839]) { // Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC) unsigned int k,inv_u,i,NCS=0,num_preambles; diff --git a/openair1/PHY/LTE_TRANSPORT/prach_extern.h b/openair1/PHY/LTE_TRANSPORT/prach_extern.h index 3404646923..3403861011 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach_extern.h +++ b/openair1/PHY/LTE_TRANSPORT/prach_extern.h @@ -81,7 +81,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint32_t X_u[64][839]); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h b/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h index af8e63c3ed..74a38e58db 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_common_proto.h @@ -224,7 +224,7 @@ uint8_t get_num_prach_tdd(module_id_t Mod_id); @returns 0-1 accordingly */ /* -uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type); +uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,frame_type_t frame_type); */ /*! @@ -247,7 +247,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint32_t X_u[64][839]); diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c index efde277203..088e2c0a5e 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c @@ -64,7 +64,7 @@ extern uint16_t beta_cqi[16]; extern uint16_t beta_ri[16]; extern uint16_t beta_ack[16]; -void extract_dci1A_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) +void extract_dci1A_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint8_t harq_pid=0; uint32_t rballoc=0; @@ -182,7 +182,7 @@ void extract_dci1A_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_ pdci_info_extarcted->dai = dai; } -void extract_dci1C_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) +void extract_dci1C_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint32_t rballoc=0; @@ -222,7 +222,7 @@ void extract_dci1C_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_ pdci_info_extarcted->Ngap = Ngap; } -void extract_dci1_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) +void extract_dci1_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint32_t rballoc=0; @@ -329,7 +329,7 @@ void extract_dci1_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, void *dci_p } -void extract_dci2_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, uint8_t nb_antenna_ports_eNB, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) +void extract_dci2_info(uint8_t N_RB_DL, frame_type_t frame_type, uint8_t nb_antenna_ports_eNB, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint32_t rballoc=0; @@ -615,7 +615,7 @@ void extract_dci2_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, uint8_t nb_ } -void extract_dci2A_info(uint8_t N_RB_DL, lte_frame_type_t frame_type, uint8_t nb_antenna_ports_eNB, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) +void extract_dci2A_info(uint8_t N_RB_DL, frame_type_t frame_type, uint8_t nb_antenna_ports_eNB, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint32_t rballoc=0; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c index 82120dc3c3..4faa8367c3 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c @@ -46,7 +46,7 @@ //#define PRACH_DEBUG 1 int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf ) { - lte_frame_type_t frame_type = ue->frame_parms.frame_type; + frame_type_t frame_type = ue->frame_parms.frame_type; //uint8_t tdd_config = ue->frame_parms.tdd_config; uint16_t rootSequenceIndex = ue->frame_parms.prach_config_common.rootSequenceIndex; uint8_t prach_ConfigIndex = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h index c5d096ceb7..05a5904971 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h @@ -1669,7 +1669,7 @@ uint8_t get_num_prach_tdd(module_id_t Mod_id); @param frame_type 0-FDD, 1-TDD @returns 0-1 accordingly */ -uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type); +uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,frame_type_t frame_type); /*! \brief Helper for MAC, returns frequency index of PRACH resource in TDD for a particular configuration index @@ -1691,7 +1691,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint32_t X_u[64][839]); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index dc0f38f096..65c0ec9381 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -1567,7 +1567,7 @@ uint8_t get_num_prach_tdd(module_id_t Mod_id); @param frame_type 0-FDD, 1-TDD @returns 0-1 accordingly */ -uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type); +uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,frame_type_t frame_type); /*! \brief Helper for MAC, returns frequency index of PRACH resource in TDD for a particular configuration index @@ -1589,7 +1589,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint32_t X_u[64][839]); diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 86df85db5c..d13fe260de 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -99,7 +99,7 @@ #define NB_RX_ANTENNAS_MAX 64 -typedef enum {TDD=1,FDD=0} lte_frame_type_t; +typedef enum {TDD=1,FDD=0} frame_type_t; typedef enum {EXTENDED=1,NORMAL=0} lte_prefix_type_t; @@ -597,7 +597,7 @@ typedef struct LTE_DL_FRAME_PARMS { /// shift of pilot position in one RB uint8_t nushift; /// Frame type (0 FDD, 1 TDD) - lte_frame_type_t frame_type; + frame_type_t frame_type; /// TDD subframe assignment (0-7) (default = 3) (254=RX only, 255=TX only) uint8_t tdd_config; /// TDD S-subframe configuration (0-9) diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 7c78d20ae5..756e6b7210 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -280,7 +280,7 @@ struct NR_DL_FRAME_PARMS { uint32_t att_rx; /// total Number of Resource Block Groups: this is ceil(N_PRB/P) /// Frame type (0 FDD, 1 TDD) - lte_frame_type_t frame_type; + frame_type_t frame_type; uint8_t tdd_config; /// Cell ID uint16_t Nid_cell; diff --git a/openair1/SCHED/phy_procedures_lte_common.c b/openair1/SCHED/phy_procedures_lte_common.c index 7033c52701..9de453da94 100644 --- a/openair1/SCHED/phy_procedures_lte_common.c +++ b/openair1/SCHED/phy_procedures_lte_common.c @@ -994,7 +994,7 @@ int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subf return(isSubframeSRS); } -void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset) +void compute_srs_pos(frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset) { if(TDD == frameType) { diff --git a/openair1/SCHED/sched_common.h b/openair1/SCHED/sched_common.h index c9fc338686..9f3e6695b6 100644 --- a/openair1/SCHED/sched_common.h +++ b/openair1/SCHED/sched_common.h @@ -339,7 +339,7 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe, unsig int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subframe_tx); -void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); +void compute_srs_pos(frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); /* from here: prototype added to remove compilation warnings, doc to be written by the author of the function */ diff --git a/openair1/SCHED/sched_eNB.h b/openair1/SCHED/sched_eNB.h index de987b0ac7..efdb1bd199 100644 --- a/openair1/SCHED/sched_eNB.h +++ b/openair1/SCHED/sched_eNB.h @@ -215,7 +215,7 @@ int16_t get_target_pucch_rx_power(module_id_t module_idP, uint8_t CC_id); int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subframe_tx); -void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); +void compute_srs_pos(frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); void release_rnti_of_phy(module_id_t mod_id); /*@}*/ diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index b02f24e04e..67513b9c59 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -574,7 +574,7 @@ void get_cqipmiri_params(PHY_VARS_UE *ue, } } -PUCCH_FMT_t get_pucch_format(lte_frame_type_t frame_type, +PUCCH_FMT_t get_pucch_format(frame_type_t frame_type, lte_prefix_type_t cyclic_prefix_type, uint8_t SR_payload, uint8_t nb_cw, diff --git a/openair1/SCHED_UE/sched_UE.h b/openair1/SCHED_UE/sched_UE.h index 32702b1148..0dbb779630 100644 --- a/openair1/SCHED_UE/sched_UE.h +++ b/openair1/SCHED_UE/sched_UE.h @@ -278,7 +278,7 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe, unsig int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subframe_tx); -void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); +void compute_srs_pos(frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); /*@}*/ diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index bd2c2d66b9..50910290c3 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -415,7 +415,7 @@ int main(int argc, char **argv) { uint8_t harq_pid; uint8_t phich_ACK; uint8_t num_phich_interf = 0; - lte_frame_type_t frame_type=TDD; + frame_type_t frame_type=TDD; // int re_offset; // uint32_t *txptr; int aarx; diff --git a/openair2/COMMON/m2ap_messages_types.h b/openair2/COMMON/m2ap_messages_types.h index c70c50fc64..460dbfc4bb 100644 --- a/openair2/COMMON/m2ap_messages_types.h +++ b/openair2/COMMON/m2ap_messages_types.h @@ -354,7 +354,7 @@ typedef struct m2ap_register_mce_req_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; @@ -427,7 +427,7 @@ typedef struct m2ap_register_enb_req_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/openair2/COMMON/m3ap_messages_types.h b/openair2/COMMON/m3ap_messages_types.h index 21e24dd449..36ac8fcc9a 100644 --- a/openair2/COMMON/m3ap_messages_types.h +++ b/openair2/COMMON/m3ap_messages_types.h @@ -123,7 +123,7 @@ typedef struct m3ap_register_mce_req_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/openair2/COMMON/phy_messages_types.h b/openair2/COMMON/phy_messages_types.h index 1f040a0a77..40e4678228 100644 --- a/openair2/COMMON/phy_messages_types.h +++ b/openair2/COMMON/phy_messages_types.h @@ -70,7 +70,7 @@ typedef struct CellInfo_s { //-------------------------------------------------------------------------------------------// // eNB: ENB_APP -> PHY messages typedef struct PhyConfigurationReq_s { - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; lte_prefix_type_t prefix_type[MAX_NUM_CCs]; uint32_t downlink_frequency[MAX_NUM_CCs]; int32_t uplink_frequency_offset[MAX_NUM_CCs]; diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index ac70dee092..5b214cf95a 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -188,7 +188,7 @@ typedef struct RrcConfigurationReq_s { uint32_t rrc_inactivity_timer_thres; // for testing, maybe change later paging_drx_t default_drx; int16_t nb_cc; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint8_t tdd_config[MAX_NUM_CCs]; uint8_t tdd_config_s[MAX_NUM_CCs]; lte_prefix_type_t prefix_type[MAX_NUM_CCs]; @@ -339,7 +339,7 @@ typedef struct NbIoTRrcConfigurationReq_s { uint16_t mcc; uint16_t mnc; uint8_t mnc_digit_length; - lte_frame_type_t frame_type; + frame_type_t frame_type; uint8_t tdd_config; uint8_t tdd_config_s; lte_prefix_type_t prefix_type; diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h index 9339ab12f3..cd092b6ca8 100644 --- a/openair2/COMMON/x2ap_messages_types.h +++ b/openair2/COMMON/x2ap_messages_types.h @@ -138,7 +138,7 @@ typedef struct x2ap_register_enb_req_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; uint32_t subframeAssignment[MAX_NUM_CCs]; diff --git a/openair2/ENB_APP/RRC_config_tools.h b/openair2/ENB_APP/RRC_config_tools.h index 488441ff59..89cefeaa1f 100644 --- a/openair2/ENB_APP/RRC_config_tools.h +++ b/openair2/ENB_APP/RRC_config_tools.h @@ -38,7 +38,7 @@ typedef struct eutra_band_s { uint32_t ul_max; uint32_t dl_min; uint32_t dl_max; - lte_frame_type_t frame_type; + frame_type_t frame_type; } eutra_band_t; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 68d1f3311f..9926ec9e20 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -1352,7 +1352,7 @@ void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t } } -void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type) { +void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, frame_type_t frame_type) { if (phy_is_present(mod_id, cc_id)) { RC.eNB[mod_id][cc_id]->frame_parms.frame_type = frame_type; } else { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 79115b0a16..c15865ccfd 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -433,7 +433,7 @@ void flexran_agent_set_operating_eutra_band(mid_t mod_id, uint8_t cc_id, uint8_t void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t N_RB); /*set frame type*/ -void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type); +void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, frame_type_t frame_type); /*RRC status flexRAN*/ uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 434a2896de..2c486ec832 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -346,7 +346,7 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) { // prepare DL Allocation lists nr_rrc_config_dl_tda(scc); - lte_frame_type_t frame_type = get_frame_type((int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + frame_type_t frame_type = get_frame_type((int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); if (frame_type == FDD) { ASN_STRUCT_FREE(asn_DEF_NR_TDD_UL_DL_ConfigCommon, scc->tdd_UL_DL_ConfigurationCommon); scc->tdd_UL_DL_ConfigurationCommon = NULL; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index b25efbb5d8..581930b83d 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -3092,7 +3092,7 @@ int is_nr_DL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon,slo else return(slot_in_period <= slots1+tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSlots ? 1 : 0); } -int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slot, lte_frame_type_t frame_type) { +int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slot, frame_type_t frame_type) { int period,period1,period2=0; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 0f2cb42b88..e8a3af2498 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -45,7 +45,7 @@ int16_t fill_dmrs_mask(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Position,i int is_nr_DL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon,slot_t slotP); -int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slotP, lte_frame_type_t frame_type); +int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slotP, frame_type_t frame_type); uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDLBWP, const NR_BWP_UplinkCommon_t *initialULBWP, diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 3b10167e03..bd693e4d88 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -323,7 +323,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; mac->frequency_range = band<100?FR1:FR2; - lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); // cell config diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index fc2c2d2c8b..99cbdf3292 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -369,7 +369,7 @@ typedef struct { NR_ControlResourceSet_t *coreset[MAX_NUM_BWP][FAPI_NR_MAX_CORESET_PER_BWP]; NR_SearchSpace_t *SSpace[MAX_NUM_BWP][FAPI_NR_MAX_SS]; - lte_frame_type_t frame_type; + frame_type_t frame_type; /*BWP*/ // dedicated active DL BWP diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 6ba8629718..a2cbd4807f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -233,7 +233,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; frequency_range_t frequency_range = band<100?FR1:FR2; - lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); RC.nrmac[Mod_idP]->common_channels[0].frame_type = frame_type; // Cell configuration diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index ca197b224d..3d17e966a9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -399,7 +399,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot, uint16_t *msg2_frame, uint16_t *msg2_slot, NR_ServingCellConfigCommon_t *scc, - lte_frame_type_t frame_type, + frame_type_t frame_type, uint16_t monitoring_slot_period, uint16_t monitoring_offset,uint8_t beam_index, uint8_t num_active_ssb, @@ -525,7 +525,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - lte_frame_type_t frame_type = cc->frame_type; + frame_type_t frame_type = cc->frame_type; uint8_t total_RApreambles = MAX_NUM_NR_PRACH_PREAMBLES; uint8_t num_ssb_per_RO = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present; @@ -933,7 +933,7 @@ void nr_get_Msg3alloc(module_id_t module_id, uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes - lte_frame_type_t frame_type = RC.nrmac[module_id]->common_channels->frame_type; + frame_type_t frame_type = RC.nrmac[module_id]->common_channels->frame_type; int mu = ubwp ? ubwp->bwp_Common->genericParameters.subcarrierSpacing : diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5aace1d0dc..7806d6011d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -62,7 +62,7 @@ void calculate_preferred_dl_tda(module_id_t module_id, const NR_BWP_Downlink_t * /* there is a mixed slot only when in TDD */ NR_ServingCellConfigCommon_t *scc = nrmac->common_channels->ServingCellConfigCommon; - lte_frame_type_t frame_type = nrmac->common_channels->frame_type; + frame_type_t frame_type = nrmac->common_channels->frame_type; const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 9273c38de3..7342864763 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -55,7 +55,7 @@ void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ub /* there is a mixed slot only when in TDD */ NR_ServingCellConfigCommon_t *scc = nrmac->common_channels->ServingCellConfigCommon; - lte_frame_type_t frame_type = nrmac->common_channels->frame_type; + frame_type_t frame_type = nrmac->common_channels->frame_type; const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; NR_ServingCellConfigCommonSIB_t *scc_sib1 = get_softmodem_params()->sa ? diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 0f538131dd..0ed70444b1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -202,7 +202,7 @@ typedef struct { int p_gNB; int Ncp; int nr_band; - lte_frame_type_t frame_type; + frame_type_t frame_type; uint64_t dl_CarrierFreq; NR_BCCH_BCH_Message_t *mib; NR_BCCH_DL_SCH_Message_t *sib1; diff --git a/openair2/M2AP/m2ap_MCE_defs.h b/openair2/M2AP/m2ap_MCE_defs.h index 5267232d69..73183e89c2 100644 --- a/openair2/M2AP/m2ap_MCE_defs.h +++ b/openair2/M2AP/m2ap_MCE_defs.h @@ -170,7 +170,7 @@ typedef struct m2ap_MCE_instance_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/openair2/M2AP/m2ap_eNB_defs.h b/openair2/M2AP/m2ap_eNB_defs.h index b8f7e4b3c6..0b30c33d80 100644 --- a/openair2/M2AP/m2ap_eNB_defs.h +++ b/openair2/M2AP/m2ap_eNB_defs.h @@ -181,7 +181,7 @@ typedef struct m2ap_eNB_instance_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c index 9b9e267828..f24c9ab1b6 100644 --- a/openair2/RRC/LTE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c @@ -1757,7 +1757,7 @@ int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance && RC.rrc[instance]->configuration.mnc[j] == S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc && RC.rrc[instance]->configuration.tac == S1AP_PAGING_IND(msg_p).tac[tai_size]) { for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - lte_frame_type_t frame_type = RC.eNB[instance][CC_id]->frame_parms.frame_type; + frame_type_t frame_type = RC.eNB[instance][CC_id]->frame_parms.frame_type; /* get nB from configuration */ /* get default DRX cycle from configuration */ Tc = (uint8_t)RC.rrc[instance]->configuration.radioresourceconfig[CC_id].pcch_defaultPagingCycle; diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index bb2a180146..54fb5a168b 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -216,7 +216,7 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc){ - lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); int curr_bwp = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; // coreset duration setting to be improved in the framework of RRC harmonization, potentially using a common function int len_coreset = 1; @@ -253,7 +253,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ uint8_t DELTA[4]= {2,3,4,6}; // Delta parameter for Msg3 int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; - lte_frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation)); pusch_timedomainresourceallocation->k2 = CALLOC(1,sizeof(long)); diff --git a/openair2/UTIL/OCG/OCG.h b/openair2/UTIL/OCG/OCG.h index 58cc7184e7..452581bb17 100644 --- a/openair2/UTIL/OCG/OCG.h +++ b/openair2/UTIL/OCG/OCG.h @@ -700,7 +700,7 @@ typedef struct { unsigned int n_frames_flag; // if set, then let the emulation goes to infinity node_function_t node_function[MAX_NUM_CCs]; node_timing_t node_timing[MAX_NUM_CCs]; - unsigned char frame_type[MAX_NUM_CCs]; //! LTE frame type (TDD=1, FDD=0). \note this should be converted to \ref lte_frame_type_t (header file reorganization needed) + unsigned char frame_type[MAX_NUM_CCs]; //! LTE frame type (TDD=1, FDD=0). \note this should be converted to \ref frame_type_t (header file reorganization needed) char *frame_type_name[MAX_NUM_CCs]; unsigned char tdd_config[MAX_NUM_CCs]; unsigned char tdd_config_S[MAX_NUM_CCs]; diff --git a/openair2/X2AP/x2ap_eNB_defs.h b/openair2/X2AP/x2ap_eNB_defs.h index 063302d03a..bd6092e0cb 100644 --- a/openair2/X2AP/x2ap_eNB_defs.h +++ b/openair2/X2AP/x2ap_eNB_defs.h @@ -172,7 +172,7 @@ typedef struct x2ap_eNB_instance_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; uint32_t subframeAssignment[MAX_NUM_CCs]; diff --git a/openair3/M3AP/m3ap_MCE_defs.h b/openair3/M3AP/m3ap_MCE_defs.h index 18ad70a408..4dcb2b4db0 100644 --- a/openair3/M3AP/m3ap_MCE_defs.h +++ b/openair3/M3AP/m3ap_MCE_defs.h @@ -170,7 +170,7 @@ typedef struct m3ap_MCE_instance_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/openair3/M3AP/m3ap_MME_defs.h b/openair3/M3AP/m3ap_MME_defs.h index 3b5725655d..6608587cc3 100644 --- a/openair3/M3AP/m3ap_MME_defs.h +++ b/openair3/M3AP/m3ap_MME_defs.h @@ -170,7 +170,7 @@ typedef struct m3ap_MME_instance_s { int32_t uplink_frequency_offset[MAX_NUM_CCs]; uint32_t Nid_cell[MAX_NUM_CCs]; int16_t N_RB_DL[MAX_NUM_CCs]; - lte_frame_type_t frame_type[MAX_NUM_CCs]; + frame_type_t frame_type[MAX_NUM_CCs]; uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; int num_cc; diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 9010a40bf9..eaeb22d096 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -111,7 +111,7 @@ typedef struct eutra_band_s { uint32_t ul_max; uint32_t dl_min; uint32_t dl_max; - lte_frame_type_t frame_type; + frame_type_t frame_type; } eutra_band_t; typedef struct band_info_s { From 8e4c513805a12a7757aaed9f8bc278d337f30427 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 18:07:45 +0100 Subject: [PATCH 091/226] Fix RRC processing time when using F1 split --- openair2/RRC/NR/rrc_gNB.c | 140 ++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 65 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0670765d1b..ab61116924 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -732,19 +732,21 @@ rrc_gNB_generate_defaultRRCReconfiguration( LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - rrc->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - rrc->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - NR_RRC_RECONFIGURATION_DELAY_MS); + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + rrc->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + rrc->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1012,19 +1014,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - rrc->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - rrc->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - NR_RRC_RECONFIGURATION_DELAY_MS); + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + rrc->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + rrc->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1199,19 +1203,21 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - NR_RRC_RECONFIGURATION_DELAY_MS); + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { @@ -1317,19 +1323,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - NR_RRC_RECONFIGURATION_DELAY_MS); + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ if (nas_length > 0) { @@ -1882,19 +1890,21 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - NR_RRC_RECONFIGURATION_DELAY_MS); + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + rrc_mac_config_req_gNB(ctxt_pP->module_id, + 0, + RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, + 0, + 0, + 0, + RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, + NULL, + NULL, + 0, + ue_context_pP->ue_context.rnti, + NULL, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { From 709db95112d98af9cacc08574fe0b715afaa27e5 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 19 Apr 2022 18:59:56 +0100 Subject: [PATCH 092/226] Fix DL/UL failure due to wrong dedicated BWP when an RA fails on Msg4 and then succeeds --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index eaf3f6d421..7dd05e29e6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2807,14 +2807,42 @@ void nr_csirs_scheduling(int Mod_idP, void nr_mac_update_timers(module_id_t module_id, frame_t frame, sub_frame_t slot) { + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; const NR_list_t *UE_list = &UE_info->list; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer--; + if (sched_ctrl->rrc_processing_timer == 0) { + LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); + + // If needed, update the Dedicated BWP + const int current_bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; + const int current_ubwp_id = sched_ctrl->active_ubwp ? sched_ctrl->active_ubwp->bwp_Id : 0; + if(UE_info->CellGroup[UE_id] && + UE_info->CellGroup[UE_id]->spCellConfig && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { + const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated; + if(*servingCellConfig->firstActiveDownlinkBWP_Id != current_bwp_id) { + sched_ctrl->active_bwp = servingCellConfig->downlinkBWP_ToAddModList->list.array[*servingCellConfig->firstActiveDownlinkBWP_Id - 1]; + LOG_I(NR_MAC, "Changing to DL-BWP %li\n", sched_ctrl->active_bwp->bwp_Id); + } + if(*servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id != current_ubwp_id) { + sched_ctrl->active_ubwp = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList->list.array[*servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id - 1]; + LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); + } + } + sched_ctrl->update_pdsch_ps = true; sched_ctrl->update_pusch_ps = true; } From 32b2f76c578ae6f2443d6cb9f3aac6f63a9a6625 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 20 Apr 2022 14:30:13 +0200 Subject: [PATCH 093/226] fix(ci): first port to the new Eurecom infrastructure: * Proxy no longer required for git cloning * Most of the IP addresses have been changed - Remaining --> 192.168.18.89 for amariue Signed-off-by: Raphael Defosseux --- ci-scripts/build_fr1_template.yaml | 2 +- ci-scripts/ci_ueinfra.yaml | 6 +-- ci-scripts/cls_containerize.py | 46 +++++++++---------- .../enb.band38.lte_2x2.100PRB.usrpn310.conf | 2 +- ...nb.band38.lte_2x2_tm2.100PRB.usrpn310.conf | 2 +- .../enb.band38.nsa_2x2.100PRB.usrpn310.conf | 2 +- ...sci_gnb.band78.sa.fr1.106PRB.usrpn310.conf | 2 +- ...oxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf | 2 +- .../gNB_SA_n78_106PRB.2x2_usrpn310.conf | 6 +-- .../gNB_SA_n78_133PRB.2x2_usrpn310.conf | 6 +-- .../gnb.band78.nsa_2x2.106PRB.usrpn310.conf | 2 +- ...and78.sa.fr1.106PRB.2x2.usrpn310.asue.conf | 2 +- ...gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf | 2 +- .../gnb.band78.sa.fr1.106PRB.usrpn310.conf | 2 +- ...gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf | 2 +- ci-scripts/main.py | 14 +++--- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 4 +- .../fr1_nsa_2x2_quectel_attach_detach.xml | 4 +- .../xml_files/fr1_sa_amarisoft_ue_1x.xml | 2 +- ci-scripts/xml_files/fr1_sa_oaiue_b200.xml | 2 +- ci-scripts/xml_files/fr1_sa_oaiue_n310.xml | 4 +- ci-scripts/xml_files/fr1_sa_oaiue_x300.xml | 2 +- ci-scripts/xml_files/fr1_sa_quectel.xml | 2 +- .../xml_files/fr1_sa_quectel_162prb.xml | 2 +- .../xml_files/fr1_sa_quectel_stages.xml | 2 +- .../fr1_sa_quectel_stages_162prb.xml | 2 +- ci-scripts/xml_files/lte_2x2_tm1_quectel.xml | 2 +- ci-scripts/xml_files/lte_2x2_tm2_quectel.xml | 2 +- .../4g_rfsimulator_fdd_05MHz/README.md | 2 +- .../docker-compose.yml | 2 +- .../docker-compose.yml | 2 +- .../docker-compose.yml | 2 +- .../docker-compose.yml | 2 +- .../5g_f1_rfsimulator/docker-compose.yaml | 2 +- .../5g_fdd_rfsimulator/docker-compose.yaml | 2 +- ci-scripts/yaml_files/5g_l2sim_tdd/README.md | 8 ++-- .../5g_l2sim_tdd/docker-compose.yaml | 6 +-- .../5g_rfsimulator/docker-compose.yaml | 2 +- .../fr1_epc_20897/docker-compose.yml | 2 +- .../magma_nsa_20897/docker-compose.yml | 2 +- .../nsa_b200_enb/docker-compose.yml | 4 +- .../nsa_b200_gnb/docker-compose.yml | 4 +- 42 files changed, 86 insertions(+), 86 deletions(-) diff --git a/ci-scripts/build_fr1_template.yaml b/ci-scripts/build_fr1_template.yaml index 02e49bc4b5..5c7b2fc6f4 100755 --- a/ci-scripts/build_fr1_template.yaml +++ b/ci-scripts/build_fr1_template.yaml @@ -14,7 +14,7 @@ steps: ADB: #on Caracal - ADBIPAddress : 192.168.18.196 + ADBIPAddress : 172.21.16.132 ADBUserName : oaici ADBPassword : KkexF6CErOi1fNuebCPsuIVK diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 89bda5fa92..b58e14ff6a 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -12,7 +12,7 @@ idefix: LogStore : /media/usb-drive/ci_qlogs PLMN : 22201 UENetwork : wwan0 - HostIPAddress : 192.168.18.188 + HostIPAddress : 172.21.16.135 HostUsername : oaicicd HostPassword : oaicicd HostSourceCodePath : none @@ -32,7 +32,7 @@ nrmodule2_quectel: LogStore : /media/ci_qlogs PLMN : 20897 UENetwork : wwan0 - HostIPAddress : 192.168.18.189 + HostIPAddress : 172.21.16.139 HostUsername : nrmodule2 HostPassword : linux HostSourceCodePath : none @@ -97,7 +97,7 @@ dummy: DetachScript : '' PLMN : 22201 UENetwork : wwan0 - HostIPAddress : 192.168.18.188 + HostIPAddress : 172.21.16.135 HostUsername : oaicicd HostPassword : oaicicd HostSourceCodePath : none diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 8092febe39..89a3ac586d 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -243,7 +243,7 @@ class Containerize(): # Build the base image only on Push Events (not on Merge Requests) # On when the base image docker file is being modified. if forceBaseImageBuild: - mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target ' + baseImage + ' --tag ' + baseImage + ':' + baseTag + ' --file docker/Dockerfile.base' + self.dockerfileprefix + ' --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > cmake_targets/log/ran-base.log 2>&1', '\$', 1600) + mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target ' + baseImage + ' --tag ' + baseImage + ':' + baseTag + ' --file docker/Dockerfile.base' + self.dockerfileprefix + ' . > cmake_targets/log/ran-base.log 2>&1', '\$', 1600) # First verify if the base image was properly created. status = True mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' ' + baseImage + ':' + baseTag, '\$', 5) @@ -1146,19 +1146,19 @@ class Containerize(): mySSH.open(ipAddr, userName, password) # Check if route to asterix gnb exists mySSH.command('ip route | grep --colour=never "192.168.68.64/26"', '\$', 10) - result = re.search('192.168.18.194', mySSH.getBefore()) + result = re.search('172.21.16.127', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 192.168.18.194 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 172.21.16.127 dev eno1', '\$', 10) # Check if route to obelix enb exists mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10) - result = re.search('192.168.18.193', mySSH.getBefore()) + result = re.search('172.21.16.128', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 172.21.16.128 dev eno1', '\$', 10) # Check if route to nepes gnb exists mySSH.command('ip route | grep --colour=never "192.168.68.192/26"', '\$', 10) - result = re.search('192.168.18.209', mySSH.getBefore()) + result = re.search('172.21.16.137', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 192.168.18.209 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 172.21.16.137 dev eno1', '\$', 10) # Check if forwarding is enabled mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10) result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore()) @@ -1174,19 +1174,19 @@ class Containerize(): mySSH.open(ipAddr, userName, password) # Check if route to porcepix epc exists mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10) - result = re.search('192.168.18.210', mySSH.getBefore()) + result = re.search('172.21.16.136', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev em1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 172.21.16.136 dev em1', '\$', 10) # Check if route to porcepix cn5g exists mySSH.command('ip route | grep --colour=never "192.168.70.128/26"', '\$', 10) - result = re.search('192.168.18.210', mySSH.getBefore()) + result = re.search('172.21.16.136', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.70.128/26 via 192.168.18.210 dev em1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.70.128/26 via 172.21.16.136 dev em1', '\$', 10) # Check if X2 route to obelix enb exists mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10) - result = re.search('192.168.18.193', mySSH.getBefore()) + result = re.search('172.21.16.128', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev em1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 172.21.16.128 dev em1', '\$', 10) # Check if forwarding is enabled mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10) result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore()) @@ -1202,19 +1202,19 @@ class Containerize(): mySSH.open(ipAddr, userName, password) # Check if route to porcepix epc exists mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10) - result = re.search('192.168.18.210', mySSH.getBefore()) + result = re.search('172.21.16.136', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 172.21.16.136 dev eno1', '\$', 10) # Check if X2 route to asterix gnb exists mySSH.command('ip route | grep --colour=never "192.168.68.64/26"', '\$', 10) - result = re.search('192.168.18.194', mySSH.getBefore()) + result = re.search('172.21.16.127', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 192.168.18.194 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 172.21.16.127 dev eno1', '\$', 10) # Check if X2 route to nepes gnb exists mySSH.command('ip route | grep --colour=never "192.168.68.192/26"', '\$', 10) - result = re.search('192.168.18.209', mySSH.getBefore()) + result = re.search('172.21.16.137', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 192.168.18.209 dev eno1', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 172.21.16.137 dev eno1', '\$', 10) # Check if forwarding is enabled mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10) result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore()) @@ -1230,14 +1230,14 @@ class Containerize(): mySSH.open(ipAddr, userName, password) # Check if route to porcepix epc exists mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10) - result = re.search('192.168.18.210', mySSH.getBefore()) + result = re.search('172.21.16.136', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev enp0s31f6', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 172.21.16.136 dev enp0s31f6', '\$', 10) # Check if X2 route to obelix enb exists mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10) - result = re.search('192.168.18.193', mySSH.getBefore()) + result = re.search('172.21.16.128', mySSH.getBefore()) if result is None: - mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev enp0s31f6', '\$', 10) + mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 172.21.16.128 dev enp0s31f6', '\$', 10) # Check if forwarding is enabled mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10) result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore()) diff --git a/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf b/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf index fe2e031acb..a7100a97e3 100644 --- a/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf +++ b/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf @@ -237,7 +237,7 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 75; eNB_instances = [0]; - sdr_addrs = "mgmt_addr=192.168.18.241,addr=192.168.20.2,second_addr=192.168.10.2"; + sdr_addrs = "mgmt_addr=172.21.19.13,addr=192.168.20.2,second_addr=192.168.10.2"; } ); diff --git a/ci-scripts/conf_files/enb.band38.lte_2x2_tm2.100PRB.usrpn310.conf b/ci-scripts/conf_files/enb.band38.lte_2x2_tm2.100PRB.usrpn310.conf index a0742c57a6..1f358c1571 100644 --- a/ci-scripts/conf_files/enb.band38.lte_2x2_tm2.100PRB.usrpn310.conf +++ b/ci-scripts/conf_files/enb.band38.lte_2x2_tm2.100PRB.usrpn310.conf @@ -237,7 +237,7 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 75; eNB_instances = [0]; - sdr_addrs = "mgmt_addr=192.168.18.241,addr=192.168.20.2,second_addr=192.168.10.2"; + sdr_addrs = "mgmt_addr=172.21.19.13,addr=192.168.20.2,second_addr=192.168.10.2"; } ); diff --git a/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf b/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf index dfc9beda71..f7088aee52 100644 --- a/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf +++ b/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf @@ -237,7 +237,7 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 75; eNB_instances = [0]; - sdr_addrs = "mgmt_addr=192.168.18.241,addr=192.168.20.2,second_addr=192.168.10.2"; + sdr_addrs = "mgmt_addr=172.21.19.13,addr=192.168.20.2,second_addr=192.168.10.2"; } ); diff --git a/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf index 40f6f911b1..51ffb1d5cd 100644 --- a/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -239,7 +239,7 @@ RUs = ( #beamforming 1x4 matrix: bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; #clock_src = "external"; - sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf index edcd4f06ff..f80ce3751a 100644 --- a/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -240,7 +240,7 @@ RUs = ( #beamforming 1x4 matrix: bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; #clock_src = "external"; - sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf index 33ab30887f..d6edc09286 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf @@ -209,9 +209,9 @@ gNBs = { GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; - GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.18.194/24"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.127/24"; GNB_INTERFACE_NAME_FOR_NGU = "em1"; - GNB_IPV4_ADDRESS_FOR_NGU = "192.168.18.194/24"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.127/24"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 }; @@ -258,7 +258,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf index 4a5eaec89b..7f4b11c35d 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf @@ -206,9 +206,9 @@ gNBs = { GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; - GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.18.194/24"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.127/24"; GNB_INTERFACE_NAME_FOR_NGU = "em1"; - GNB_IPV4_ADDRESS_FOR_NGU = "192.168.18.194/24"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.127/24"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 }; @@ -254,7 +254,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf index 21863dcfc7..e3bd49e7fc 100644 --- a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf @@ -230,7 +230,7 @@ RUs = ( bf_weights = [0x00007fff, 0x00007fff]; #clock_src = "external"; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf index 60fb16318f..5e6b3fb217 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf @@ -264,7 +264,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf index 1d7c4b57f0..8489008300 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf @@ -261,7 +261,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf index e2b331939b..9e1f499f03 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -263,7 +263,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf index 324b3d2ce1..ce63578dd3 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf @@ -262,7 +262,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); diff --git a/ci-scripts/main.py b/ci-scripts/main.py index c838c3740d..65f9fbb0da 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -779,19 +779,19 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re HTML.CreateHtmlTabHeader() # On CI bench w/ containers, we need to validate if IP routes are set - if EPC.IPAddress == '192.168.18.210': + if EPC.IPAddress == '172.21.16.136': CONTAINERS.CheckAndAddRoute('porcepix', EPC.IPAddress, EPC.UserName, EPC.Password) - if CONTAINERS.eNBIPAddress == '192.168.18.194': + if CONTAINERS.eNBIPAddress == '172.21.16.127': CONTAINERS.CheckAndAddRoute('asterix', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword) - if CONTAINERS.eNB1IPAddress == '192.168.18.194': + if CONTAINERS.eNB1IPAddress == '172.21.16.127': CONTAINERS.CheckAndAddRoute('asterix', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password) - if CONTAINERS.eNBIPAddress == '192.168.18.193': + if CONTAINERS.eNBIPAddress == '172.21.16.128': CONTAINERS.CheckAndAddRoute('obelix', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword) - if CONTAINERS.eNB1IPAddress == '192.168.18.193': + if CONTAINERS.eNB1IPAddress == '172.21.16.128': CONTAINERS.CheckAndAddRoute('obelix', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password) - if CONTAINERS.eNBIPAddress == '192.168.18.209': + if CONTAINERS.eNBIPAddress == '172.21.16.137': CONTAINERS.CheckAndAddRoute('nepes', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword) - if CONTAINERS.eNB1IPAddress == '192.168.18.209': + if CONTAINERS.eNB1IPAddress == '172.21.16.137': CONTAINERS.CheckAndAddRoute('nepes', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password) CiTestObj.FailReportCnt = 0 diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index 56694920ba..a4dcb58e8b 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -68,7 +68,7 @@ lte yes yes - 192.168.18.241 + 172.21.19.13 @@ -81,7 +81,7 @@ nr yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14
diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml index 840521481e..335fe873a1 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml @@ -87,7 +87,7 @@ lte yes yes - 192.168.18.241 + 172.21.19.13 @@ -100,7 +100,7 @@ nr yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_amarisoft_ue_1x.xml b/ci-scripts/xml_files/fr1_sa_amarisoft_ue_1x.xml index 194ed4e453..ea031a0174 100644 --- a/ci-scripts/xml_files/fr1_sa_amarisoft_ue_1x.xml +++ b/ci-scripts/xml_files/fr1_sa_amarisoft_ue_1x.xml @@ -52,7 +52,7 @@ yes yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_oaiue_b200.xml b/ci-scripts/xml_files/fr1_sa_oaiue_b200.xml index 55268b909d..5995f75a64 100644 --- a/ci-scripts/xml_files/fr1_sa_oaiue_b200.xml +++ b/ci-scripts/xml_files/fr1_sa_oaiue_b200.xml @@ -60,7 +60,7 @@ nr yes yes - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_oaiue_n310.xml b/ci-scripts/xml_files/fr1_sa_oaiue_n310.xml index 53b696c6eb..468005f54f 100644 --- a/ci-scripts/xml_files/fr1_sa_oaiue_n310.xml +++ b/ci-scripts/xml_files/fr1_sa_oaiue_n310.xml @@ -42,7 +42,7 @@ Initialize_OAI_UE Initialize OAI UE (N310) nr - --sa -O ../../../ci-scripts/conf_files/ue.sa.conf --usrp-args "mgmt_addr=192.168.18.241,addr=192.168.10.2" --numerology 1 -r 106 --band 78 -C 3319680000 --nokrnmod 1 --ue-txgain 0 --ue-rxgain 70 --ue-fo-compensation --log_config.global_log_options level,nocolor,time + --sa -O ../../../ci-scripts/conf_files/ue.sa.conf --usrp-args "mgmt_addr=172.21.19.13,addr=192.168.10.2" --numerology 1 -r 106 --band 78 -C 3319680000 --nokrnmod 1 --ue-txgain 0 --ue-rxgain 70 --ue-fo-compensation --log_config.global_log_options level,nocolor,time @@ -60,7 +60,7 @@ nr yes yes - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_oaiue_x300.xml b/ci-scripts/xml_files/fr1_sa_oaiue_x300.xml index 8c2f7052e4..ef001a7518 100644 --- a/ci-scripts/xml_files/fr1_sa_oaiue_x300.xml +++ b/ci-scripts/xml_files/fr1_sa_oaiue_x300.xml @@ -60,7 +60,7 @@ nr yes yes - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml index 576456ebc9..4d4edab56b 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel.xml @@ -70,7 +70,7 @@ yes yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml index c5f2ddad5f..23eaccfcfd 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml @@ -68,7 +68,7 @@ yes yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml index 2707fd4ebf..603f3f919b 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml @@ -74,7 +74,7 @@ yes yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_stages_162prb.xml b/ci-scripts/xml_files/fr1_sa_quectel_stages_162prb.xml index 661bcb32fe..9371e46ec9 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_stages_162prb.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_stages_162prb.xml @@ -74,7 +74,7 @@ yes yes datalog_rt_stats.2x2.yaml - 192.168.18.252 + 172.21.19.14 diff --git a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml index 11c4abce1b..6aa53200c8 100644 --- a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml @@ -65,7 +65,7 @@ lte yes yes - 192.168.18.241 + 172.21.19.13 diff --git a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml index 714cf51a9b..84aa87aa23 100644 --- a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml @@ -65,7 +65,7 @@ lte yes yes - 192.168.18.241 + 172.21.19.13 diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md index 400559d269..be0d63838b 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md @@ -505,7 +505,7 @@ In my traffic test, I was able to ping outside of my local network. in SPGW-C config: ```yaml - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' ``` diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml index b15e794c10..a260857a34 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml @@ -115,7 +115,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml index e1e992c94c..3f63953b0e 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml @@ -115,7 +115,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml index ad665813f2..1165400273 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml @@ -115,7 +115,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml index ffa92bac49..86f6c80b59 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml @@ -115,7 +115,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml index 74a23905f0..d52b228ec6 100644 --- a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml @@ -120,7 +120,7 @@ services: - SMF_INTERFACE_PORT_FOR_SBI=80 - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 - SMF_API_VERSION=v1 - - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + - DEFAULT_DNS_IPV4_ADDRESS=172.21.3.100 - DEFAULT_DNS_SEC_IPV4_ADDRESS=4.4.4.4 - AMF_IPV4_ADDRESS=0.0.0.0 - AMF_PORT=80 diff --git a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml index 3e46adb9e7..7758c39592 100644 --- a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml @@ -120,7 +120,7 @@ services: - SMF_INTERFACE_PORT_FOR_SBI=80 - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 - SMF_API_VERSION=v1 - - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + - DEFAULT_DNS_IPV4_ADDRESS=172.21.3.100 - DEFAULT_DNS_SEC_IPV4_ADDRESS=4.4.4.4 - AMF_IPV4_ADDRESS=0.0.0.0 - AMF_PORT=80 diff --git a/ci-scripts/yaml_files/5g_l2sim_tdd/README.md b/ci-scripts/yaml_files/5g_l2sim_tdd/README.md index 531f2406ef..f1e1287995 100644 --- a/ci-scripts/yaml_files/5g_l2sim_tdd/README.md +++ b/ci-scripts/yaml_files/5g_l2sim_tdd/README.md @@ -326,16 +326,16 @@ Removing network l2sim-oai-traffic-net In the `SMF` section, provide your own DNS IP address: ```yaml - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS=172.21.3.100 ``` -In the `gNB` section, provide your docker-host primary IP address and interface name: in our case `192.168.18.193` and `eno1`. +In the `gNB` section, provide your docker-host primary IP address and interface name: in our case `172.21.16.128` and `eno1`. ```yaml GNB_NGA_IF_NAME: eno1 - GNB_NGA_IP_ADDRESS: 192.168.18.193 + GNB_NGA_IP_ADDRESS: 172.21.16.128 GNB_NGU_IF_NAME: eno1 - GNB_NGU_IP_ADDRESS: 192.168.18.193 + GNB_NGU_IP_ADDRESS: 172.21.16.128 ``` Same thing in the `nr-ue` section: diff --git a/ci-scripts/yaml_files/5g_l2sim_tdd/docker-compose.yaml b/ci-scripts/yaml_files/5g_l2sim_tdd/docker-compose.yaml index c899f8cc7e..a28b640e1a 100644 --- a/ci-scripts/yaml_files/5g_l2sim_tdd/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_l2sim_tdd/docker-compose.yaml @@ -120,7 +120,7 @@ services: - SMF_INTERFACE_PORT_FOR_SBI=80 - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 - SMF_API_VERSION=v1 - - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + - DEFAULT_DNS_IPV4_ADDRESS=172.21.3.100 - DEFAULT_DNS_SEC_IPV4_ADDRESS=4.4.4.4 - AMF_IPV4_ADDRESS=0.0.0.0 - AMF_PORT=80 @@ -241,9 +241,9 @@ services: NSSAI_SD1: 112233 AMF_IP_ADDRESS: 192.168.71.132 GNB_NGA_IF_NAME: eno1 - GNB_NGA_IP_ADDRESS: 192.168.18.193 + GNB_NGA_IP_ADDRESS: 172.21.16.128 GNB_NGU_IF_NAME: eno1 - GNB_NGU_IP_ADDRESS: 192.168.18.193 + GNB_NGU_IP_ADDRESS: 172.21.16.128 LOCAL_S_IF_NAME: 'lo:' REMOTE_S_ADDRESS: 127.0.0.1 LOCAL_S_ADDRESS: 127.0.0.2 diff --git a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml index f27ec3050d..696d8c6698 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml @@ -120,7 +120,7 @@ services: - SMF_INTERFACE_PORT_FOR_SBI=80 - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 - SMF_API_VERSION=v1 - - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + - DEFAULT_DNS_IPV4_ADDRESS=172.21.3.100 - DEFAULT_DNS_SEC_IPV4_ADDRESS=4.4.4.4 - AMF_IPV4_ADDRESS=0.0.0.0 - AMF_PORT=80 diff --git a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml index a3675dc78e..91d15b5251 100644 --- a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml +++ b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml @@ -132,7 +132,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml index df14e900e7..f320e7e3df 100644 --- a/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml +++ b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml @@ -116,7 +116,7 @@ services: TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 + DEFAULT_DNS_IPV4_ADDRESS: 172.21.3.100 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 PUSH_PROTOCOL_OPTION: 'true' APN_NI_1: oai.ipv4 diff --git a/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml index 92ccdf8a0a..2df5eac61b 100644 --- a/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml +++ b/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml @@ -20,7 +20,7 @@ services: NB_PRB: 25 ENABLE_MEASUREMENT_REPORTS: 'yes' ENABLE_X2: 'yes' - MME_S1C_IP_ADDRESS: 192.168.18.210 + MME_S1C_IP_ADDRESS: 172.21.16.136 ENB_S1C_IF_NAME: eth0 ENB_S1C_IP_ADDRESS: 192.168.68.130 ENB_S1U_IF_NAME: eth0 @@ -29,7 +29,7 @@ services: RRC_INACTIVITY_THRESHOLD: 0 FLEXRAN_ENABLED: 'no' FLEXRAN_INTERFACE_NAME: eth0 - FLEXRAN_IPV4_ADDRESS: 192.168.18.210 + FLEXRAN_IPV4_ADDRESS: 172.21.16.136 THREAD_PARALLEL_CONFIG: PARALLEL_SINGLE_THREAD USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time,line_num,function volumes: diff --git a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml index c6096956a8..61266aa2b1 100644 --- a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml @@ -15,7 +15,7 @@ services: TAC: 1 ENABLE_X2: 'yes' ENB_X2_IP_ADDRESS: 192.168.68.130 - MME_S1C_IP_ADDRESS: 192.168.18.210 + MME_S1C_IP_ADDRESS: 172.21.16.136 GNB_S1C_IF_NAME: eth0 GNB_S1C_IP_ADDRESS: 192.168.68.194 GNB_S1U_IF_NAME: eth0 @@ -24,7 +24,7 @@ services: RRC_INACTIVITY_THRESHOLD: 0 FLEXRAN_ENABLED: 'no' FLEXRAN_INTERFACE_NAME: eth0 - FLEXRAN_IPV4_ADDRESS: 192.168.18.210 + FLEXRAN_IPV4_ADDRESS: 172.21.16.136 THREAD_PARALLEL_CONFIG: PARALLEL_RU_L1_TRX_SPLIT USE_ADDITIONAL_OPTIONS: -E -q --RUs.[0].sdr_addrs serial=30C51D4 --log_config.global_log_options level,nocolor,time,line_num,function volumes: From efd99acacc0a5fb9dd7af5753f47de5abade6252 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 20 Apr 2022 15:51:02 +0100 Subject: [PATCH 094/226] Fix read SSpace array index at -1 --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 6 ++++-- openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c | 6 +++--- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 941efb1b8d..c60b6e153c 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -560,7 +560,8 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, AssertFatal(ss->searchSpaceType != NULL, "ss->searchSpaceType is null\n"); AssertFatal(ss->monitoringSymbolsWithinSlot != NULL, "NR_SearchSpace->monitoringSymbolsWithinSlot is null\n"); AssertFatal(ss->monitoringSymbolsWithinSlot->buf != NULL, "NR_SearchSpace->monitoringSymbolsWithinSlot->buf is null\n"); - mac->SSpace[dl_bwp_id-1][ss->searchSpaceId - 1] = ss; + AssertFatal(ss->searchSpaceId <= FAPI_NR_MAX_SS, "Invalid searchSpaceId\n"); + mac->SSpace[dl_bwp_id][ss->searchSpaceId - 1] = ss; } struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; @@ -575,7 +576,8 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, AssertFatal(css->searchSpaceType != NULL, "css->searchSpaceType is null\n"); AssertFatal(css->monitoringSymbolsWithinSlot != NULL, "css->monitoringSymbolsWithinSlot is null\n"); AssertFatal(css->monitoringSymbolsWithinSlot->buf != NULL, "css->monitoringSymbolsWithinSlot->buf is null\n"); - mac->SSpace[dl_bwp_id-1][css->searchSpaceId - 1] = css; + AssertFatal(css->searchSpaceId <= FAPI_NR_MAX_SS, "Invalid searchSpaceId\n"); + mac->SSpace[dl_bwp_id][css->searchSpaceId - 1] = css; } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 1ef8a36377..fce6efa103 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -102,7 +102,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t ss_id,mac->ra.ss->searchSpaceId); } else - ss = mac->SSpace[dl_bwp_id-1][ss_id-1]; + ss = mac->SSpace[dl_bwp_id][ss_id-1]; } else ss = mac->search_space_zero; @@ -277,12 +277,12 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl if (bwpd) { for (ss_id = 1; ss_id <= FAPI_NR_MAX_SS; ss_id++){ - if(mac->SSpace[bwp_id-1][ss_id-1]==NULL) { + if(mac->SSpace[bwp_id][ss_id-1]==NULL) { continue; } LOG_D(NR_MAC, "[DCI_CONFIG] ss_id %d\n",ss_id); - NR_SearchSpace_t *ss = mac->SSpace[bwp_id-1][ss_id-1]; + NR_SearchSpace_t *ss = mac->SSpace[bwp_id][ss_id-1]; AssertFatal(ss_id == ss->searchSpaceId,"SS IDs don't correspond\n"); fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15; NR_SetupRelease_PDCCH_ConfigCommon_t *pdcch_ConfigCommon = bwp_Common->pdcch_ConfigCommon; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 8424197643..dbf6c3c953 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2642,7 +2642,7 @@ int get_n_rb(NR_UE_MAC_INST_t *mac, int rnti_type){ case NR_RNTI_P: { if (mac->DLbwp[dl_bwp_id-1]->bwp_Common->pdcch_ConfigCommon->choice.setup->controlResourceSetZero) { uint8_t coreset_id = 0; // assuming controlResourceSetId is 0 for controlResourceSetZero - NR_ControlResourceSet_t *coreset = mac->coreset[dl_bwp_id-1][coreset_id]; + NR_ControlResourceSet_t *coreset = mac->coreset[dl_bwp_id][coreset_id]; get_coreset_rballoc(coreset->frequencyDomainResources.buf,&N_RB,&start_RB); } else { N_RB = NRRIV2BW(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); From 15777bbf0e8910b36e9ee7b83579ca9dea6311fb Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Apr 2022 17:05:03 +0200 Subject: [PATCH 095/226] fix for ulsim antenna ports --- openair1/SIMULATION/NR_PHY/ulsim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 1a027a33d5..ade4e2aad4 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -730,7 +730,7 @@ int main(int argc, char **argv) // TODO do a UECAP for phy-sim const gNB_RrcConfigurationReq conf = { - .pdsch_AntennaPorts = { .N1 = n_tx, .N2 = 1, .XP = 1 }, + .pdsch_AntennaPorts = { .N1 = 1, .N2 = 1, .XP = 1 }, .pusch_AntennaPorts = n_rx, .minRXTXTIME = 0, .do_CSIRS = 0, @@ -751,10 +751,10 @@ int main(int argc, char **argv) rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); // UE dedicated configuration rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); - frame_parms->nb_antennas_tx = n_tx; + frame_parms->nb_antennas_tx = 1; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - cfg->carrier_config.num_tx_ant.value = n_tx; + cfg->carrier_config.num_tx_ant.value = 1; cfg->carrier_config.num_rx_ant.value = n_rx; // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,0,0x01); phy_init_nr_gNB(gNB,0,1); @@ -771,6 +771,8 @@ int main(int argc, char **argv) PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*)); PHY_vars_UE_g[0][0] = UE; memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); + UE->frame_parms.nb_antennas_tx = n_tx; + frame_parms->nb_antennas_rx = 1; if (init_nr_ue_signal(UE, 1) != 0) { printf("Error at UE NR initialisation\n"); From d592b1ff5bcb8743129006bb43a5a2501b5a14ec Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 20 Apr 2022 17:56:25 +0200 Subject: [PATCH 096/226] fix(ci): dummy commit to re-trigger Signed-off-by: Raphael Defosseux --- ci-scripts/ci_ueinfra.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index b58e14ff6a..b888f6bb59 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -40,6 +40,7 @@ nrmodule2_quectel: - sudo -S ip link set dev wwan1 mtu 1500 MTU : 1500 +# CAUTION: 192.168.18.89 address has to be changed when the server is moved #single UE single ping amarisoft_ue_1: ID: amarisoft_ue_1 From 588754153857ebe7d58eaa3955c7996cf2b27d65 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 20 Apr 2022 17:16:49 +0100 Subject: [PATCH 097/226] Fix segmentation fault when using multiple Dedicated-BWPs and F1 --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index a954ced6a9..bec1d36fe9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -58,7 +58,7 @@ void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ub lte_frame_type_t frame_type = nrmac->common_channels->frame_type; const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - NR_ServingCellConfigCommonSIB_t *scc_sib1 = get_softmodem_params()->sa ? + NR_ServingCellConfigCommonSIB_t *scc_sib1 = nrmac->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1->servingCellConfigCommon : NULL; AssertFatal(scc!=NULL || scc_sib1!=NULL,"We need one serving cell config common\n"); From f49df054566bc7dc1df20a98a3d191f5001e3dd4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Apr 2022 18:55:38 +0200 Subject: [PATCH 098/226] fix for ulschsim antenna ports --- openair1/SIMULATION/NR_PHY/ulschsim.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index 3f8062a0ce..d76d438446 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -391,8 +391,6 @@ int main(int argc, char **argv) initTpool(tp_param, gNB->threadPool, true); initNotifiedFIFO(gNB->respDecode); frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) - frame_parms->nb_antennas_tx = n_tx; - frame_parms->nb_antennas_rx = n_rx; frame_parms->N_RB_DL = N_RB_DL; frame_parms->N_RB_UL = N_RB_UL; frame_parms->Ncp = extended_prefix_flag ? EXTENDED : NORMAL; @@ -400,6 +398,9 @@ int main(int argc, char **argv) memcpy(&gNB->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); + gNB->frame_parms.nb_antennas_tx = 1; + gNB->frame_parms.nb_antennas_rx = n_rx; + nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions); phy_init_nr_gNB(gNB, 0, 1); //lowmem @@ -408,6 +409,9 @@ int main(int argc, char **argv) UE = malloc(sizeof(PHY_VARS_NR_UE)); memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); + UE->frame_parms.nb_antennas_tx = n_tx; + UE->frame_parms.nb_antennas_rx = 1; + //phy_init_nr_top(frame_parms); if (init_nr_ue_signal(UE, 1) != 0) { printf("Error at UE NR initialisation.\n"); From aeaf4c87b574c22219ad380df63006cfb273e527 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 20 Apr 2022 20:19:56 +0100 Subject: [PATCH 099/226] Fix delay of CU for a very large cellGroupConfig --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f20e5bf239..c728ebd076 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -2220,9 +2220,7 @@ int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, &asn_DEF_NR_CellGroupConfig, //might be added prefix later (void **)&cellGroupConfig, (uint8_t *)masterCellGroup_from_DU->buf, - masterCellGroup_from_DU->size, 0, 0); - - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)cellGroupConfig); + masterCellGroup_from_DU->size, 0, 0); } else { cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); @@ -2249,8 +2247,10 @@ int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, ue_p->masterCellGroup = cellGroupConfig; if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)cellGroupConfig); xer_fprint(stdout, &asn_DEF_NR_DL_CCCH_Message, (void *)&dl_ccch_msg); } + enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_CCCH_Message, NULL, (void *)&dl_ccch_msg, From b8ac9d5db9a171424000ae9015abb500f89ae853 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 21 Apr 2022 12:30:08 +0200 Subject: [PATCH 100/226] fix(ci): fix helm charts for phy-sim testing on cluster new infra Signed-off-by: Raphael Defosseux --- charts/physims/charts/dlsim/values.yaml | 4 +-- charts/physims/charts/ldpctest/values.yaml | 4 +-- charts/physims/charts/nr-dlschsim/values.yaml | 4 +-- charts/physims/charts/nr-dlsim/values.yaml | 4 +-- charts/physims/charts/nr-pbchsim/values.yaml | 4 +-- charts/physims/charts/nr-prachsim/values.yaml | 4 +-- charts/physims/charts/nr-pucchsim/values.yaml | 4 +-- charts/physims/charts/nr-ulschsim/values.yaml | 4 +-- charts/physims/charts/nr-ulsim/values.yaml | 4 +-- charts/physims/charts/polartest/values.yaml | 4 +-- .../physims/charts/smallblocktest/values.yaml | 4 +-- charts/physims/charts/ulsim/values.yaml | 4 +-- charts/physims/templates/rbac.yaml | 30 ++++++++++++++----- charts/physims/values.yaml | 4 +-- ci-scripts/cls_physim1.py | 30 +++++++++++++------ 15 files changed, 69 insertions(+), 43 deletions(-) diff --git a/charts/physims/charts/dlsim/values.yaml b/charts/physims/charts/dlsim/values.yaml index d78fbb7409..7f45b42f72 100644 --- a/charts/physims/charts/dlsim/values.yaml +++ b/charts/physims/charts/dlsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/ldpctest/values.yaml b/charts/physims/charts/ldpctest/values.yaml index e2e6467923..b3cc476cf8 100644 --- a/charts/physims/charts/ldpctest/values.yaml +++ b/charts/physims/charts/ldpctest/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-dlschsim/values.yaml b/charts/physims/charts/nr-dlschsim/values.yaml index 8944e7e724..b7ef28f47a 100644 --- a/charts/physims/charts/nr-dlschsim/values.yaml +++ b/charts/physims/charts/nr-dlschsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-dlsim/values.yaml b/charts/physims/charts/nr-dlsim/values.yaml index 573e8630de..2a35912fee 100644 --- a/charts/physims/charts/nr-dlsim/values.yaml +++ b/charts/physims/charts/nr-dlsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-pbchsim/values.yaml b/charts/physims/charts/nr-pbchsim/values.yaml index 28c4678334..9a25d2810d 100644 --- a/charts/physims/charts/nr-pbchsim/values.yaml +++ b/charts/physims/charts/nr-pbchsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-prachsim/values.yaml b/charts/physims/charts/nr-prachsim/values.yaml index 9e3c68b54d..dba6cc16c0 100644 --- a/charts/physims/charts/nr-prachsim/values.yaml +++ b/charts/physims/charts/nr-prachsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-pucchsim/values.yaml b/charts/physims/charts/nr-pucchsim/values.yaml index 449670f713..77fe0963ac 100644 --- a/charts/physims/charts/nr-pucchsim/values.yaml +++ b/charts/physims/charts/nr-pucchsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-ulschsim/values.yaml b/charts/physims/charts/nr-ulschsim/values.yaml index a3afc090e8..efb011a7f6 100644 --- a/charts/physims/charts/nr-ulschsim/values.yaml +++ b/charts/physims/charts/nr-ulschsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/nr-ulsim/values.yaml b/charts/physims/charts/nr-ulsim/values.yaml index 2bf96498e8..71c455b69c 100644 --- a/charts/physims/charts/nr-ulsim/values.yaml +++ b/charts/physims/charts/nr-ulsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/polartest/values.yaml b/charts/physims/charts/polartest/values.yaml index e0a532fdd8..e0751e8ec4 100644 --- a/charts/physims/charts/polartest/values.yaml +++ b/charts/physims/charts/polartest/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/smallblocktest/values.yaml b/charts/physims/charts/smallblocktest/values.yaml index f2f113d9b6..f933a978fd 100644 --- a/charts/physims/charts/smallblocktest/values.yaml +++ b/charts/physims/charts/smallblocktest/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/charts/ulsim/values.yaml b/charts/physims/charts/ulsim/values.yaml index 35dc14d596..d25b6fc2a5 100644 --- a/charts/physims/charts/ulsim/values.yaml +++ b/charts/physims/charts/ulsim/values.yaml @@ -4,11 +4,11 @@ replicaCount: 1 -namespace: "oaicicd-ran-tmp" +namespace: "OAICICD_PROJECT" image: registry: local - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: temp # pullPolicy: IfNotPresent or Never or Always pullPolicy: Always diff --git a/charts/physims/templates/rbac.yaml b/charts/physims/templates/rbac.yaml index 35f956a203..b341744796 100644 --- a/charts/physims/templates/rbac.yaml +++ b/charts/physims/templates/rbac.yaml @@ -1,12 +1,26 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role metadata: - name: {{ .Chart.Name }}-{{ .Values.global.namespace }}-rbac -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin + name: {{ .Chart.Name }}-{{ .Release.Namespace }}-role +rules: +- apiGroups: + - security.openshift.io + resourceNames: + - privileged + resources: + - securitycontextconstraints + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Chart.Name }}-{{ .Release.Namespace }}-binding subjects: - kind: ServiceAccount name: {{ .Values.global.serviceAccountName }} - namespace: {{ .Values.global.namespace }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ .Chart.Name }}-{{ .Release.Namespace }}-role + apiGroup: rbac.authorization.k8s.io diff --git a/charts/physims/values.yaml b/charts/physims/values.yaml index b348e822bb..d5253c7812 100644 --- a/charts/physims/values.yaml +++ b/charts/physims/values.yaml @@ -4,9 +4,9 @@ global: serviceAccountName: oai-physim-sa - namespace: "oaicicd-ran-tmp" + namespace: "OAICICD_PROJECT" image: - repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim + repository: image-registry.openshift-image-registry.svc:5000/OAICICD_PROJECT/oai-physim version: TAG ## Declaring values specific to coressponding physim to overwrite diff --git a/ci-scripts/cls_physim1.py b/ci-scripts/cls_physim1.py index 83fb74b7cb..54329790cd 100644 --- a/ci-scripts/cls_physim1.py +++ b/ci-scripts/cls_physim1.py @@ -153,6 +153,7 @@ class PhySim: mySSH.command(f'oc project {ocProjectName}', '\$', 30) if mySSH.getBefore().count(f'Already on project "{ocProjectName}"') == 0 and mySSH.getBefore().count(f'Now using project "{self.OCProjectName}"') == 0: logging.error(f'\u001B[1m Unable to access OC project {ocProjectName}\u001B[0m') + mySSH.command('oc logout', '\$', 30) mySSH.close() HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_PROJECT_FAIL) RAN.prematureExit = True @@ -161,9 +162,10 @@ class PhySim: logging.debug(f'\u001B[1m Now using project {ocProjectName}\u001B[0m') # Tag the image and push to the OC cluster - mySSH.command('oc whoami -t | sudo podman login -u ' + ocUserName + ' --password-stdin https://default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/ --tls-verify=false', '\$', 30) + mySSH.command('oc whoami -t | sudo podman login -u ' + ocUserName + ' --password-stdin https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/ --tls-verify=false', '\$', 30) if mySSH.getBefore().count('Login Succeeded!') == 0: logging.error('\u001B[1m Podman Login to OC Cluster Registry Failed\u001B[0m') + mySSH.command('oc logout', '\$', 30) mySSH.close() HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_LOGIN_FAIL) RAN.prematureExit = True @@ -171,9 +173,11 @@ class PhySim: else: logging.debug('\u001B[1m Podman Login to OC Cluster Registry Successfully\u001B[0m') time.sleep(2) - mySSH.command('oc create -f openshift/oai-physim-image-stream.yml', '\$', 30) + mySSH.command('oc create -f openshift/oai-physim-image-stream.yml || true', '\$', 30) if mySSH.getBefore().count('(AlreadyExists):') == 0 and mySSH.getBefore().count('created') == 0: logging.error(f'\u001B[1m Image Stream "oai-physim" Creation Failed on OC Cluster {ocProjectName}\u001B[0m') + mySSH.command('sudo podman logout https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/', '\$', 6) + mySSH.command('oc logout', '\$', 30) mySSH.close() HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_IS_FAIL) RAN.prematureExit = True @@ -181,11 +185,13 @@ class PhySim: else: logging.debug(f'\u001B[1m Image Stream "oai-physim" created on OC project {ocProjectName}\u001B[0m') time.sleep(2) - mySSH.command(f'sudo podman tag oai-physim:{imageTag} default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30) + mySSH.command(f'sudo podman tag oai-physim:{imageTag} default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30) time.sleep(2) - mySSH.command(f'sudo podman push default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag} --tls-verify=false', '\$', 180) + mySSH.command(f'sudo podman push default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag} --tls-verify=false', '\$', 180) if mySSH.getBefore().count('Storing signatures') == 0: logging.error('\u001B[1m Image "oai-physim" push to OC Cluster Registry Failed\u001B[0m') + mySSH.command('sudo podman logout https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/', '\$', 6) + mySSH.command('oc logout', '\$', 30) mySSH.close() HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_IS_FAIL) RAN.prematureExit = True @@ -195,8 +201,9 @@ class PhySim: # Using helm charts deployment time.sleep(5) + mySSH.command(f'grep -rl OAICICD_PROJECT ./charts/ | xargs sed -i -e "s#OAICICD_PROJECT#{ocProjectName}#"', '\$', 30) mySSH.command(f'sed -i -e "s#TAG#{imageTag}#g" ./charts/physims/values.yaml', '\$', 6) - mySSH.command('helm install physim ./charts/physims/ | tee -a cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 30) + mySSH.command('helm install physim ./charts/physims/ 2>&1 | tee -a cmake_targets/log/physim_helm_summary.txt', '\$', 30) if mySSH.getBefore().count('STATUS: deployed') == 0: logging.error('\u001B[1m Deploying PhySim Failed using helm chart on OC Cluster\u001B[0m') mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 30) @@ -206,8 +213,10 @@ class PhySim: mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True) if re.search('No resources found', mySSH.getBefore()): isFinished1 = True - mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30) + mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30) mySSH.command('oc delete is oai-physim', '\$', 30) + mySSH.command('sudo podman logout https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/', '\$', 6) + mySSH.command('oc logout', '\$', 30) mySSH.close() self.AnalyzeLogFile_phySim(HTML) RAN.prematureExit = True @@ -227,7 +236,7 @@ class PhySim: if isRunning == False: logging.error('\u001B[1m Some PODS Running FAILED \u001B[0m') mySSH.command('oc get pods -l app.kubernetes.io/instance=physim 2>&1 | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 6) - mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6) + mySSH.command('helm uninstall physim 2>&1 >> cmake_targets/log/physim_helm_summary.txt', '\$', 6) self.AnalyzeLogFile_phySim(HTML) isFinished1 = False while(isFinished1 == False): @@ -235,8 +244,10 @@ class PhySim: mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True) if re.search('No resources found', mySSH.getBefore()): isFinished1 = True - mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6) + mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6) mySSH.command('oc delete is oai-physim', '\$', 6) + mySSH.command('sudo podman logout https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/', '\$', 6) + mySSH.command('oc logout', '\$', 30) HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_PHYSIM_DEPLOY_FAIL) HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult) RAN.prematureExit = True @@ -293,9 +304,10 @@ class PhySim: isFinished1 = True if isFinished1 == True: logging.debug('\u001B[1m UnDeployed PhySim Successfully on OC Cluster\u001B[0m') - mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6) + mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6) mySSH.command('oc delete is oai-physim', '\$', 6) logging.debug('\u001B[1m Deleted the Image and ImageStream\u001B[0m') + mySSH.command('sudo podman logout https://default-route-openshift-image-registry.apps.oai.cs.eurecom.fr/', '\$', 6) mySSH.command('oc logout', '\$', 6) mySSH.close() self.AnalyzeLogFile_phySim(HTML) From 9327e9915210ee6480b66bcf88567b4bea501948 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 21 Apr 2022 16:29:22 +0200 Subject: [PATCH 101/226] additional fixes for SR --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index bcf743b560..5026354afd 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -422,9 +422,9 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, if (pucch_pdu->bit_len_harq==0) { uci_pdu->harq = NULL; uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); - uci_pdu->sr->sr_confidence_level = (SNRtimes10 > uci_stats->pucch0_thres) ? 1 : 0; + uci_pdu->sr->sr_confidence_level = (SNRtimes10 < uci_stats->pucch0_thres); uci_stats->pucch0_sr_trials++; - if (xrtmag_dBtimes10>10*max_n0) { + if (xrtmag_dBtimes10>(10*max_n0+100)) { uci_pdu->sr->sr_indication = 1; uci_stats->pucch0_positive_SR++; LOG_D(PHY,"PUCCH0 got positive SR. Cumulative number of positive SR %d\n", uci_stats->pucch0_positive_SR); From 4b4e419aba60c857ca4f9ecaee4eba87ef283c85 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 14 Apr 2022 16:42:38 +0200 Subject: [PATCH 102/226] nr rlc: fix NR RLC AM status generation Several problems were found and fixed. --- openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 107 +++++++++++++--------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index af8cb5715a..bfc8abbf73 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -908,8 +908,6 @@ typedef struct { int so_start; int sn_end; int so_end; - /* data for maximum ack */ - int ack_sn; /* -1 if not to be used */ /* pdu to use for next call to 'next_missing' */ nr_rlc_pdu_t *next; } missing_data_t; @@ -924,13 +922,12 @@ static missing_data_t next_missing(nr_rlc_entity_am_t *entity, int max_so = 0; int last_reached = 0; - ret.ack_sn = -1; - /* special case: missing part before the head of RX list */ if (check_head) { if (cur->sn != entity->rx_next || !cur->is_first) { /* don't report if out of reporting window */ - if (sn_compare_rx(entity, entity->rx_highest_status, cur->sn) <= 0) { + if (sn_compare_rx(entity, entity->rx_highest_status, + entity->rx_next) <= 0) { ret.sn_start = -1; return ret; } @@ -954,10 +951,6 @@ next_pdu: max_so = cur_max_so; last_reached = last_reached | cur->is_last; - /* if cur already processed, it can be the acked SDU */ - if (cur->data == NULL) - ret.ack_sn = (cur->sn + 1) % entity->sn_modulus; - /* no next? */ if (cur->next == NULL) { /* inform the caller that work is over */ @@ -1033,32 +1026,36 @@ next_pdu: } /* discontinuity between different SDUs */ - ret.sn_start = sn; + if (last_reached) { + ret.sn_start = (sn + 1) % entity->sn_modulus; + ret.so_start = 0; + } else { + ret.sn_start = sn; + ret.so_start = max_so + 1; + } /* don't report if out of reporting window */ if (sn_compare_rx(entity, entity->rx_highest_status, ret.sn_start) <= 0) { ret.sn_start = -1; return ret; } - ret.so_start = max_so + 1; set_end_different_sdu: - /* don't go more than rx_highest_status - 1 */ - if (sn_compare_rx(entity, entity->rx_highest_status, cur->sn) <= 0) { - ret.sn_end = (entity->rx_highest_status - 1 + entity->sn_modulus) % - entity->sn_modulus; - ret.so_end = 0xffff; - return ret; - } - /* if cur is the head of a SDU, then use cur-1 */ if (cur->is_first) { ret.sn_end = (cur->sn - 1 + entity->sn_modulus) % entity->sn_modulus; ret.so_end = 0xffff; - return ret; + } else { + ret.sn_end = cur->sn; + ret.so_end = cur->so - 1; + } + /* don't go more than rx_highest_status - 1 */ + if (sn_compare_rx(entity, entity->rx_highest_status, ret.sn_end) <= 0) { + ret.sn_end = (entity->rx_highest_status - 1 + entity->sn_modulus) % + entity->sn_modulus; + ret.so_end = 0xffff; + ret.next = NULL; } - ret.sn_end = cur->sn; - ret.so_end = cur->so - 1; return ret; } @@ -1098,21 +1095,20 @@ static void get_e1_position(nr_rlc_entity_am_t *entity, } } -/* returns the number of nacks serialized. - * In most cases it is 1, it can be more if the - * missing data consists of a range that is more - * than 255 SNs in which case it has to be cut in - * smaller ranges. +/* returns the last nack SN generated, -1 if nothing generated. * If there is no more room in the status buffer, * will set m->next = NULL (and may serialize - * less nacks than required by 'm'). + * less nacks than required by 'm'), also + * sets *generation_truncated to 1. */ static int generate_missing(nr_rlc_entity_am_t *entity, nr_rlc_pdu_encoder_t *encoder, - missing_data_t *m, int *e1_byte, int *e1_bit) + missing_data_t *m, int *e1_byte, int *e1_bit, + int *generation_truncated, + unsigned char **so_end_address) { int r_bits = entity->sn_field_length == 18 ? 3 : 1; - int range_count = 0; + int last_nack_generated = -1; int sn_start; int so_start; int sn_end; @@ -1164,6 +1160,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity, m_nack.so_end = so_end; if (encoder->byte + nack_size(entity, &m_nack) > encoder->size) { m->next = NULL; + *generation_truncated = 1; break; } @@ -1197,6 +1194,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity, /* nack_sn */ nr_rlc_pdu_encoder_put_bits(encoder, sn_start, entity->sn_field_length); + last_nack_generated = sn_start; /* e1 = 0 (set later if needed) */ nr_rlc_pdu_encoder_put_bits(encoder, 0, 1); /* e2 */ @@ -1208,34 +1206,44 @@ static int generate_missing(nr_rlc_entity_am_t *entity, /* so_start/so_end */ if (e2) { nr_rlc_pdu_encoder_put_bits(encoder, so_start, 16); + *so_end_address = (unsigned char *)encoder->buffer + encoder->byte; nr_rlc_pdu_encoder_put_bits(encoder, so_end, 16); - } + } else + *so_end_address = NULL; /* nack range */ - if (e3) + if (e3) { nr_rlc_pdu_encoder_put_bits(encoder, cur_sn_count, 8); + last_nack_generated += cur_sn_count - 1; + } sn_count -= cur_sn_count; sn_start = (sn_start + cur_sn_count) % entity->sn_modulus; - range_count++; } - return range_count; + return last_nack_generated; } static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size) { - int ack_sn = entity->rx_next; - missing_data_t m; + int last_nack; + int ack_sn; + missing_data_t m; nr_rlc_pdu_t *cur; - int nack_count = 0; + int check_head = 1; nr_rlc_pdu_encoder_t encoder; int e1_byte; int e1_bit; + int generation_truncated; + int ln; + unsigned char *so_end_address = NULL; /* if not enough room, do nothing */ if (size < 3) return 0; + /* initial last_nack is rx_next - 1 */ + last_nack = (entity->rx_next - 1 + entity->sn_modulus) % entity->sn_modulus; + nr_rlc_pdu_encoder_init(&encoder, buffer, size); /* first 3 bytes, ack_sn and e1 will be set later */ @@ -1250,22 +1258,33 @@ static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size) e1_bit = entity->sn_field_length == 18 ? 1 : 7; while (cur != NULL) { - m = next_missing(entity, cur, nack_count == 0); - - /* update ack_sn if the returned value is valid */ - if (m.ack_sn != -1) - ack_sn = m.ack_sn; + m = next_missing(entity, cur, check_head); + check_head = 0; /* stop here if no more nack to report */ if (m.sn_start == -1) break; - nack_count += generate_missing(entity, &encoder, &m, &e1_byte, &e1_bit); + generation_truncated = 0; + ln = generate_missing(entity, &encoder, &m, &e1_byte, &e1_bit, + &generation_truncated, &so_end_address); + /* remember the last nack put, if any */ + if (ln != -1) + last_nack = ln; + /* if generation was truncated and so_end was put, we force its value to + * 0xffff (end of SDU) because we don't know what missing nack information + * was supposed to be put, so we nack until the end of the PDU to be sure + */ + if (generation_truncated && so_end_address != NULL) { + so_end_address[0] = 0xff; + so_end_address[1] = 0xff; + } cur = m.next; } - /* put ack_sn */ + /* put ack_sn, which is last_nack + 1 */ + ack_sn = (last_nack + 1) % entity->sn_modulus; if (entity->sn_field_length == 12) { buffer[0] = ack_sn >> 8; buffer[1] = ack_sn & 255; From f57f4ce3fedaef00e374db58d0e2e9b41870b2c0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Apr 2022 09:56:54 +0200 Subject: [PATCH 103/226] bugfix in channel compensation --- openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index b415374dc7..db05e03d4c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -721,7 +721,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128); ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],1); - ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128); + ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128b); ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); From 4c4cbc963b99080682ea10c00c31cd7540e8ebd2 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 22 Apr 2022 12:28:04 +0200 Subject: [PATCH 104/226] fix(ci): little fixes after migration to new infra: - Better mechanism for qlog cleaning - Faster attachment check - html.py is confusing for some python3 installation -- renaming it Signed-off-by: Raphael Defosseux --- ci-scripts/cls_log_mgt.py | 23 ++++++++++++++--------- ci-scripts/cls_module_ue.py | 7 ++++--- ci-scripts/{html.py => cls_oai_html.py} | 0 ci-scripts/cls_oaicitest.py | 4 ++-- ci-scripts/cls_physim.py | 2 +- ci-scripts/cls_physim1.py | 2 +- ci-scripts/main.py | 4 ++-- 7 files changed, 24 insertions(+), 18 deletions(-) rename ci-scripts/{html.py => cls_oai_html.py} (100%) diff --git a/ci-scripts/cls_log_mgt.py b/ci-scripts/cls_log_mgt.py index 905a105512..e29e9168b7 100644 --- a/ci-scripts/cls_log_mgt.py +++ b/ci-scripts/cls_log_mgt.py @@ -64,10 +64,10 @@ class Log_Mgt: if m is not None: return int(m.group(1)) - def __RemoveOldest(self): + def __RemoveOldest(self, days): mySSH = sshconnection.SSHConnection() mySSH.open(self.IPAddress, self.Username, self.Password) - COMMAND='echo ' + self.Password + ' | sudo -S find ' + self.path + ' -type f -mtime +14 -delete' + COMMAND='echo ' + self.Password + ' | sudo -S find ' + self.path + ' -type f -mtime +' + str(days) + ' -delete' mySSH.command(COMMAND,'\$',20) mySSH.close() @@ -79,13 +79,18 @@ class Log_Mgt: def LogRotation(self): - used_space = self.__CheckUsedSpace() #avail space in target folder - if used_space > 80 : - logging.debug('\u001B[1;37;41m Used Disk > 80%, on ' + self.Username+'@'+self.IPAddress + '\u001B[0m') - logging.debug('\u001B[1;37;41m Removing Artifacts older than 14 days \u001B[0m') - self.__RemoveOldest() - else: - logging.debug('Used Disk < 80%, on ' + self.Username+'@'+self.IPAddress +', no cleaning required') + doLoop = True + nbDays = 14 + while doLoop and nbDays > 2: + used_space = self.__CheckUsedSpace() #avail space in target folder + if used_space > 80 : + logging.debug('\u001B[1;37;41m Used Disk (' + str(used_space) + '%) > 80%, on ' + self.Username+'@'+self.IPAddress + '\u001B[0m') + logging.debug('\u001B[1;37;41m Removing Artifacts older than ' + nbDays + ' days \u001B[0m') + self.__RemoveOldest(nbDays) + nbDays -= 1 + else: + logging.debug('Used Disk (' + str(used_space) + '%) < 80%, on ' + self.Username+'@'+self.IPAddress +', no cleaning required') + doLoop = False diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index fb10700798..dcf75a34fc 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -107,14 +107,15 @@ class Module_UE: def GetModuleIPAddress(self): HOST=self.HostUsername+'@'+self.HostIPAddress response= [] - tentative = 3 + tentative = 8 while (len(response)==0) and (tentative>0): COMMAND="ip a show dev " + self.UENetwork + " | grep --colour=never inet | grep " + self.UENetwork - logging.debug(COMMAND) + if tentative == 8: + logging.debug(COMMAND) ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) response = ssh.stdout.readlines() tentative-=1 - time.sleep(10) + time.sleep(2) if (tentative==0) and (len(response)==0): logging.debug('\u001B[1;37;41m Module IP Address Not Found! Time expired \u001B[0m') return -1 diff --git a/ci-scripts/html.py b/ci-scripts/cls_oai_html.py similarity index 100% rename from ci-scripts/html.py rename to ci-scripts/cls_oai_html.py diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 33910f1f9b..9d5ae84038 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -439,7 +439,7 @@ class OaiCiTest(): while cnt < 4: Module_UE.Command("wup") logging.debug("Waiting for IP address to be assigned") - time.sleep(20) + time.sleep(5) logging.debug("Retrieve IP address") status=Module_UE.GetModuleIPAddress() if status==0: @@ -1111,7 +1111,7 @@ class OaiCiTest(): while cnt < 4: Module_UE.Command("wup") logging.debug("Waiting for IP address to be assigned") - time.sleep(20) + time.sleep(5) logging.debug("Retrieve IP address") status=Module_UE.GetModuleIPAddress() if status==0: diff --git a/ci-scripts/cls_physim.py b/ci-scripts/cls_physim.py index 33792f6ca4..ecd8f63af1 100644 --- a/ci-scripts/cls_physim.py +++ b/ci-scripts/cls_physim.py @@ -32,7 +32,7 @@ import logging #to create a SSH object locally in the methods import sshconnection #to update the HTML object -import html +import cls_oai_html from multiprocessing import SimpleQueue #for log folder maintenance import os diff --git a/ci-scripts/cls_physim1.py b/ci-scripts/cls_physim1.py index 54329790cd..3907fc2a34 100644 --- a/ci-scripts/cls_physim1.py +++ b/ci-scripts/cls_physim1.py @@ -33,7 +33,7 @@ #----------------------------------------------------------- import logging import sshconnection as SSH -import html +import cls_oai_html import os import re import time diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 65f9fbb0da..03947bdfc9 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -49,7 +49,7 @@ import cls_physim1 #class PhySim for physical simulators deploy and run import sshconnection import epc import ran -import html +import cls_oai_html #----------------------------------------------------------- @@ -518,7 +518,7 @@ CiTestObj = cls_oaicitest.OaiCiTest() SSH = sshconnection.SSHConnection() EPC = epc.EPCManagement() RAN = ran.RANManagement() -HTML = html.HTMLManagement() +HTML = cls_oai_html.HTMLManagement() CONTAINERS = cls_containerize.Containerize() SCA = cls_static_code_analysis.StaticCodeAnalysis() PHYSIM = cls_physim1.PhySim() From 998452e679864ed8d50729736bd6639b6359fc90 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 22 Apr 2022 16:53:34 +0200 Subject: [PATCH 105/226] feat(ci): add script to properly flatten the target images Signed-off-by: Raphael Defosseux --- ci-scripts/cls_containerize.py | 3 + ci-scripts/flatten_image.py | 116 +++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 ci-scripts/flatten_image.py diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 89a3ac586d..259db7bffe 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -294,6 +294,9 @@ class Containerize(): if image != 'ran-build': mySSH.command('sed -i -e "s#' + "ran-build" + ':latest#' + "ran-build" + ':' + imageTag + '#" docker/Dockerfile.' + pattern + self.dockerfileprefix, '\$', 5) mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target ' + image + ' --tag ' + image + ':' + imageTag + ' --file docker/Dockerfile.' + pattern + self.dockerfileprefix + ' . > cmake_targets/log/' + image + '.log 2>&1', '\$', 1200) + # Flatten Image + if image != 'ran-build': + mySSH.command('python3 ./ci-scripts/flatten_image.py --tag ' + image + ':' + imageTag, '\$', 300) # split the log mySSH.command('mkdir -p cmake_targets/log/' + image, '\$', 5) mySSH.command('python3 ci-scripts/docker_log_split.py --logfilename=cmake_targets/log/' + image + '.log', '\$', 5) diff --git a/ci-scripts/flatten_image.py b/ci-scripts/flatten_image.py new file mode 100644 index 0000000000..aef5bfccad --- /dev/null +++ b/ci-scripts/flatten_image.py @@ -0,0 +1,116 @@ +""" + Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The OpenAirInterface Software Alliance licenses this file to You under + the OAI Public License, Version 1.1 (the "License"); you may not use this file + except in compliance with the License. + You may obtain a copy of the License at + + http://www.openairinterface.org/?page_id=698 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +------------------------------------------------------------------------------- + For more information about the OpenAirInterface (OAI) Software Alliance: + contact@openairinterface.org +""" + +import argparse +import re +import subprocess +import sys + +def main() -> None: + args = _parse_args() + status = perform_flattening(args.tag) + sys.exit(status) + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description='Flattening Image') + + parser.add_argument( + '--tag', '-t', + action='store', + required=True, + help='Image Tag in image-name:image tag format', + ) + return parser.parse_args() + +def perform_flattening(tag): + # First detect which docker/podman command to use + cli = '' + image_prefix = '' + cmd = 'which podman || true' + podman_check = subprocess.check_output(cmd, shell=True, universal_newlines=True) + if re.search('podman', podman_check.strip()): + cli = 'sudo podman' + image_prefix = 'localhost/' + if cli == '': + cmd = 'which docker || true' + docker_check = subprocess.check_output(cmd, shell=True, universal_newlines=True) + if re.search('docker', docker_check.strip()): + cli = 'docker' + image_prefix = '' + if cli == '': + print ('No docker / podman installed: quitting') + return -1 + print (f'Flattening {tag}') + + # Creating a container + cmd = cli + ' run --name test-flatten --entrypoint /bin/true -d ' + tag + print (cmd) + subprocess.check_output(cmd, shell=True, universal_newlines=True) + + # Export / Import trick + cmd = cli + ' export test-flatten | ' + cli + ' import ' + # Bizarro syntax issue with podman + if cli == 'docker': + cmd += ' --change "ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ' + else: + cmd += ' --change "ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ' + if re.search('oai-enb', tag): + cmd += ' --change "WORKDIR /opt/oai-enb" ' + cmd += ' --change "EXPOSE 2152/udp" ' + cmd += ' --change "EXPOSE 36412/udp" ' + cmd += ' --change "EXPOSE 36422/udp" ' + cmd += ' --change "CMD [\\"/opt/oai-enb/bin/lte-softmodem.Rel15\\", \\"-O\\", \\"/opt/oai-enb/etc/enb.conf\\"]" ' + cmd += ' --change "ENTRYPOINT [\\"/opt/oai-enb/bin/entrypoint.sh\\"]" ' + if re.search('oai-gnb', tag): + cmd += ' --change "WORKDIR /opt/oai-gnb" ' + cmd += ' --change "EXPOSE 2152/udp" ' + cmd += ' --change "EXPOSE 36422/udp" ' + cmd += ' --change "CMD [\\"/opt/oai-gnb/bin/nr-softmodem.Rel15\\", \\"-O\\", \\"/opt/oai-gnb/etc/gnb.conf\\"]" ' + cmd += ' --change "ENTRYPOINT [\\"/opt/oai-gnb/bin/entrypoint.sh\\"]" ' + if re.search('oai-lte-ue', tag): + cmd += ' --change "WORKDIR /opt/oai-lte-ue" ' + cmd += ' --change "CMD [\\"/opt/oai-lte-ue/bin/lte-uesoftmodem.Rel15\\"]" ' + cmd += ' --change "ENTRYPOINT [\\"/opt/oai-lte-ue/bin/entrypoint.sh\\"]" ' + if re.search('oai-nr-ue', tag): + cmd += ' --change "WORKDIR /opt/oai-nr-ue" ' + cmd += ' --change "CMD [\\"/opt/oai-nr-ue/bin/nr-uesoftmodem.Rel15\\", \\"-O\\", \\"/opt/oai-nr-ue/etc/nr-ue.conf\\"]" ' + cmd += ' --change "ENTRYPOINT [\\"/opt/oai-nr-ue/bin/entrypoint.sh\\"]" ' + if re.search('oai-lte-ru', tag): + cmd += ' --change "WORKDIR /opt/oai-lte-ru" ' + cmd += ' --change "CMD [\\"/opt/oai-lte-ru/bin/oairu.Rel15\\", \\"-O\\", \\"/opt/oai-lte-ru/etc/rru.conf\\"]" ' + cmd += ' --change "ENTRYPOINT [\\"/opt/oai-lte-ru/bin/entrypoint.sh\\"]" ' + if re.search('oai-physim', tag): + cmd += ' --change "WORKDIR /opt/oai-physim" ' + cmd += ' - ' + image_prefix + tag + print (cmd) + subprocess.check_output(cmd, shell=True, universal_newlines=True) + + # Remove container + cmd = cli + ' rm -f test-flatten' + print (cmd) + subprocess.check_output(cmd, shell=True, universal_newlines=True) + + # At this point the original image is a dangling image. + # CI pipeline will clean up (`image prune --force`) + return 0 + +if __name__ == '__main__': + main() From 532bb0da965417617e4e7ed2612b1208814bae3c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 22 Apr 2022 17:54:41 +0200 Subject: [PATCH 106/226] Remove useless comments --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 63f21ec382..9123afd324 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -107,10 +107,10 @@ typedef struct { } __attribute__ ((__packed__)) NR_MAC_SUBHEADER_SHORT; typedef struct { - uint8_t LCID: 6; // octet 1 [5:0] - uint8_t F: 1; // octet 1 [6] - uint8_t R: 1; // octet 1 [7] - uint16_t L: 16; // octet 2 [7:0] + uint8_t LCID: 6; + uint8_t F: 1; + uint8_t R: 1; + uint16_t L: 16; } __attribute__ ((__packed__)) NR_MAC_SUBHEADER_LONG; typedef struct { From 697d72cd01f0742f9d1cb88bc707fbf17ee8f10d Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Apr 2022 18:51:53 +0200 Subject: [PATCH 107/226] adding missing parameter in ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index ade4e2aad4..64ccffabdd 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1171,6 +1171,7 @@ int main(int argc, char **argv) ul_config.ul_config_list[0].pusch_config_pdu.mcs_table = mcs_table; ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; ul_config.ul_config_list[0].pusch_config_pdu.nrOfLayers = precod_nbr_layers; + ul_config.ul_config_list[0].pusch_config_pdu.dmrs_ports = ((1< Date: Mon, 25 Apr 2022 23:34:48 +0200 Subject: [PATCH 108/226] fix 2 bugs: one new introduced by merge develop, one introduced by extra change asked in code review --- openair1/PHY/CODING/nr_segmentation.c | 2 +- openair1/SCHED_NR_UE/harq_nr.c | 4 +++- openair1/SIMULATION/NR_PHY/dlschsim.c | 7 +------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/CODING/nr_segmentation.c b/openair1/PHY/CODING/nr_segmentation.c index 281e61cda5..f43813a6ca 100644 --- a/openair1/PHY/CODING/nr_segmentation.c +++ b/openair1/PHY/CODING/nr_segmentation.c @@ -87,7 +87,7 @@ if ((Kprime%Kb) > 0) else Z = (Kprime/Kb); - LOG_D(PHY,"nr segmetation B %u Bprime %u Kprime %u z %u \n", B, Bprime, Kprime, Z); + LOG_D(PHY,"nr segmentation B %u Bprime %u Kprime %u z %u \n", B, Bprime, Kprime, Z); if (Z <= 2) { *K = 2; diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index c0f7c08771..a9ff01d78a 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -357,8 +357,10 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int if (ndi!=dl_harq->DCINdi) { dl_harq->first_rx = true; dl_harq->DLround = 0; - } else + } else { + dl_harq->first_rx = false; dl_harq->DLround++; + } dl_harq->status = ACTIVE; diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index 64e377b896..6f747b36a6 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -478,13 +478,10 @@ int main(int argc, char **argv) harq_process->n_dmrs_cdm_groups = 1; printf("harq process ue mcs = %d Qm = %d, symb %d\n", harq_process->mcs, harq_process->Qm, nb_symb_sch); - unsigned char *test_input; - test_input = (unsigned char *) malloc16(sizeof(unsigned char) * TBS / 8); + unsigned char *test_input=dlsch->harq_process.pdu; //unsigned char test_input[TBS / 8] __attribute__ ((aligned(16))); for (i = 0; i < TBS / 8; i++) test_input[i] = (unsigned char) rand(); - dlsch->harq_process.pdu=test_input; - //estimated_output = harq_process->b; #ifdef DEBUG_NR_DLSCHSIM for (i = 0; i < TBS / 8; i++) printf("test_input[i]=%hhu \n",test_input[i]); @@ -618,8 +615,6 @@ int main(int argc, char **argv) } }*/ - //free(test_input); it must not be free as it is in DLSCH_struct -> free_gNB_dlsch () -> free(harq->pdu) with no checks or control - free_channel_desc_scm(gNB2UE); reset_DLSCH_struct(gNB, &msgDataTx); From 50612fdcc2cd8adc4fa308bc4c85aa8f00dcd377 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 26 Apr 2022 10:40:45 +0200 Subject: [PATCH 109/226] fix(ci): when deploy CN5G, health detection fixed to display the image tag/date in HTML report Signed-off-by: Raphael Defosseux --- ci-scripts/epc.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 0fc37d4ead..52583bb6d1 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -255,16 +255,19 @@ class EPCManagement(): mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5) mySSH.command('cd /opt/oai-cn5g-fed-v1.3/docker-compose', '\$', 5) mySSH.command('python3 ./core-network.py '+self.cfgDeploy, '\$', 60) - time.sleep(2) - mySSH.command('docker-compose -p 5gcn ps -a', '\$', 60) + if re.search('start-mini-as-ue', self.cfgDeploy): + dFile = 'docker-compose-mini-nrf-asue.yaml' + else: + dFile = 'docker-compose-mini-nrf.yaml' + mySSH.command('docker-compose -p 5gcn -f ' + dFile + ' ps -a', '\$', 60) if mySSH.getBefore().count('Up (healthy)') != 6: logging.error('Not all container healthy') else: - logging.debug('OK') - mySSH.command('docker-compose config | grep --colour=never image', '\$', 10) + logging.debug('OK --> all containers are healthy') + mySSH.command('docker-compose -p 5gcn -f ' + dFile + ' config | grep --colour=never image', '\$', 10) listOfImages = mySSH.getBefore() for imageLine in listOfImages.split('\\r\\n'): - res1 = re.search('image: (?P[a-zA-Z0-9\-]+):(?P[a-zA-Z0-9\-]+)', str(imageLine)) + res1 = re.search('image: (?P[a-zA-Z0-9\-/]+):(?P[a-zA-Z0-9\-]+)', str(imageLine)) res2 = re.search('mysql', str(imageLine)) if res1 is not None and res2 is None: html_cell += res1.group('name') + ':' + res1.group('tag') + ' ' From 7e6f8ecfb38514a0490f680c3f3ef2e3ecf9d015 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 26 Apr 2022 10:59:25 +0200 Subject: [PATCH 110/226] fixing bugs and cleaning up ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 219 ++++++++++++----------------- 1 file changed, 93 insertions(+), 126 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 64ccffabdd..8b30958131 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -744,13 +744,14 @@ int main(int argc, char **argv) /* RRC parameter validation for secondaryCellGroup */ fix_scd(scd); - AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); + AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); - gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; + gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, + secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); frame_parms->nb_antennas_tx = 1; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; @@ -772,7 +773,7 @@ int main(int argc, char **argv) PHY_vars_UE_g[0][0] = UE; memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); UE->frame_parms.nb_antennas_tx = n_tx; - frame_parms->nb_antennas_rx = 1; + UE->frame_parms.nb_antennas_rx = 1; if (init_nr_ue_signal(UE, 1) != 0) { printf("Error at UE NR initialisation\n"); @@ -825,7 +826,7 @@ int main(int argc, char **argv) unsigned char *estimated_output_bit; unsigned char *test_input_bit; - uint32_t errors_decoding = 0; + uint32_t errors_decoding = 0; test_input_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384); @@ -858,21 +859,14 @@ int main(int argc, char **argv) /* validate parameters othwerwise default values are used */ /* -U flag can be used to set DMRS parameters*/ - if(modify_dmrs) - { + if(modify_dmrs) { if(dmrs_arg[0] == 0) - { mapping_type = typeA; - } else if (dmrs_arg[0] == 1) - { mapping_type = typeB; - } /* Additional DMRS positions */ if(dmrs_arg[1] >= 0 && dmrs_arg[1] <=3 ) - { add_pos = dmrs_arg[1]; - } } printf("NOTE: DMRS config is modified with Mapping Type %d , Additional Position %d \n", mapping_type, add_pos ); @@ -882,24 +876,22 @@ int main(int argc, char **argv) printf("num dmrs sym %d\n",number_dmrs_symbols); uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; - if ((frame_parms->nb_antennas_tx==4)&&(precod_nbr_layers==4)) - { + if ((UE->frame_parms.nb_antennas_tx==4)&&(precod_nbr_layers==4)) num_dmrs_cdm_grps_no_data = 2; - } if (transformPrecoder == transformPrecoder_enabled) { AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); int8_t index = get_index_for_dmrs_lowpapr_seq((NR_NB_SC_PER_RB/2) * nb_rb); - AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); dmrs_config_type = pusch_dmrs_type1; printf("[ULSIM]: TRANSFORM PRECODING ENABLED. Num RBs: %d, index for DMRS_SEQ: %d\n", nb_rb, index); } - nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; + nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, precod_nbr_layers); unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); @@ -926,17 +918,12 @@ int main(int argc, char **argv) double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); /* -T option enable PTRS */ - if(enable_ptrs) - { + if(enable_ptrs) { /* validate parameters othwerwise default values are used */ if(ptrs_arg[0] == 0 || ptrs_arg[0] == 1 || ptrs_arg[0] == 2 ) - { ptrs_time_density = ptrs_arg[0]; - } if(ptrs_arg[1] == 2 || ptrs_arg[1] == 4 ) - { ptrs_freq_density = ptrs_arg[1]; - } pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; printf("NOTE: PTRS Enabled with L %d, K %d \n", ptrs_time_density, ptrs_freq_density ); } @@ -1052,7 +1039,7 @@ int main(int argc, char **argv) uint8_t round = 0; crc_status = 1; - errors_decoding = 0; + errors_decoding = 0; memset((void*)roundStats,0,50*sizeof(roundStats[0])); while (roundframe_parms, - frame_parms->nb_antennas_tx); + UE->frame_parms.nb_antennas_tx); - if (n_trials==1) - { + if (n_trials==1) { LOG_M("txsig0.m","txs0", &UE->common_vars.txdata[0][slot_offset],slot_length,1,1); LOG_M("txsig0F.m","txs0F", UE->common_vars.txdataF[0],frame_parms->ofdm_symbol_size*14,1,1); - if (precod_nbr_layers > 1) - { + if (precod_nbr_layers > 1) { LOG_M("txsig1.m","txs1", &UE->common_vars.txdata[1][slot_offset],slot_length,1,1); LOG_M("txsig1F.m","txs1F", UE->common_vars.txdataF[1],frame_parms->ofdm_symbol_size*14,1,1); - if (precod_nbr_layers==4) - { + if (precod_nbr_layers==4) { LOG_M("txsig2.m","txs2", &UE->common_vars.txdata[2][slot_offset],slot_length,1,1); LOG_M("txsig3.m","txs3", &UE->common_vars.txdata[3][slot_offset],slot_length,1,1); - LOG_M("txsig2F.m","txs2F", UE->common_vars.txdataF[2],frame_parms->ofdm_symbol_size*14,1,1); LOG_M("txsig3F.m","txs3F", UE->common_vars.txdataF[3],frame_parms->ofdm_symbol_size*14,1,1); } @@ -1241,32 +1224,28 @@ int main(int argc, char **argv) //////////////////////////////////////////////////// tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); txlev_sum = 0; - for (int aa=0; aanb_antennas_tx; aa++) - { + for (int aa=0; aanb_antennas_rx; aa++) { atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); - txlev_sum += atxlev[aa]; + txlev_sum += atxlev[aa]; if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,atxlev[aa],10*log10((double)atxlev[aa]),txlev_sum); } } else - { n_trials = 1; - } - if (input_fd == NULL ) - { + if (input_fd == NULL) { sigma_dB = 10 * log10((double)txlev_sum * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; sigma = pow(10,sigma_dB/10); if(n_trials==1) printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",sigma,sigma_dB,10*log10((double)txlev_sum),(double)(double) - frame_parms->ofdm_symbol_size/(12*nb_rb)); + frame_parms->ofdm_symbol_size/(12*nb_rb)); for (i=0; inb_antennas_tx; aa++) { + for (int aa=0; aaframe_parms.nb_antennas_tx; aa++) { s_re[aa][i] = ((double)(((short *)&UE->common_vars.txdata[aa][slot_offset]))[(i<<1)]); s_im[aa][i] = ((double)(((short *)&UE->common_vars.txdata[aa][slot_offset]))[(i<<1)+1]); } @@ -1274,17 +1253,13 @@ int main(int argc, char **argv) if (UE2gNB->max_Doppler == 0) - { multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); - } else { + else multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); - } - for (i=0; inb_antennas_rx; ap++) - { - if (channel_model == AWGN) - { + + for (i=0; inb_antennas_rx; ap++) { + if (channel_model == AWGN) { double H_awgn[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 {0.0, 1.0, 0.0, 0.0}, //rx 1 {0.0, 0.0, 1.0, 0.0}, //rx 2 @@ -1299,8 +1274,7 @@ int main(int argc, char **argv) r_re[ap][i] = 0; r_im[ap][i] = 0; - for (int aa=0; aapdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) - { + if(pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { set_ptrs_symb_idx(&ptrsSymPos, pusch_pdu->nr_of_symbols, pusch_pdu->start_symbol_index, @@ -1346,47 +1319,42 @@ int main(int argc, char **argv) ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot); - if (n_trials==1 && round==0) - { - LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1); - - LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],14*frame_parms->ofdm_symbol_size,1,1); - if (precod_nbr_layers > 1) - { - LOG_M("rxsig1.m","rx1",&gNB->common_vars.rxdata[1][slot_offset],slot_length,1,1); - LOG_M("rxsigF1.m","rxsF1",gNB->common_vars.rxdataF[1],14*frame_parms->ofdm_symbol_size,1,1); - if (precod_nbr_layers==4) - { - LOG_M("rxsig2.m","rx2",&gNB->common_vars.rxdata[2][slot_offset],slot_length,1,1); - LOG_M("rxsig3.m","rx3",&gNB->common_vars.rxdata[3][slot_offset],slot_length,1,1); - - LOG_M("rxsigF2.m","rxsF2",gNB->common_vars.rxdataF[2],14*frame_parms->ofdm_symbol_size,1,1); - LOG_M("rxsigF3.m","rxsF3",gNB->common_vars.rxdataF[3],14*frame_parms->ofdm_symbol_size,1,1); - } + if (n_trials==1 && round==0) { + LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1); + LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],14*frame_parms->ofdm_symbol_size,1,1); + if (precod_nbr_layers > 1) { + LOG_M("rxsig1.m","rx1",&gNB->common_vars.rxdata[1][slot_offset],slot_length,1,1); + LOG_M("rxsigF1.m","rxsF1",gNB->common_vars.rxdataF[1],14*frame_parms->ofdm_symbol_size,1,1); + if (precod_nbr_layers==4) { + LOG_M("rxsig2.m","rx2",&gNB->common_vars.rxdata[2][slot_offset],slot_length,1,1); + LOG_M("rxsig3.m","rx3",&gNB->common_vars.rxdata[3][slot_offset],slot_length,1,1); + LOG_M("rxsigF2.m","rxsF2",gNB->common_vars.rxdataF[2],14*frame_parms->ofdm_symbol_size,1,1); + LOG_M("rxsigF3.m","rxsF3",gNB->common_vars.rxdataF[3],14*frame_parms->ofdm_symbol_size,1,1); + } } - } + } - if (n_trials == 1 && round==0) { + if (n_trials == 1 && round==0) { #ifdef __AVX2__ - __attribute__((unused)) - int off = ((nb_rb&1) == 1)? 4:0; + __attribute__((unused)) + int off = ((nb_rb&1) == 1)? 4:0; #else - __attribute__((unused)) - int off = 0; + __attribute__((unused)) + int off = 0; #endif - LOG_M("rxsigF0_ext.m","rxsF0_ext", - &gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_M("chestF0.m","chF0", - &gNB->pusch_vars[0]->ul_ch_estimates[0][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); - LOG_M("chestT0.m","chT0", - &gNB->pusch_vars[0]->ul_ch_estimates_time[0][0],frame_parms->ofdm_symbol_size,1,1); - LOG_M("chestF0_ext.m","chF0_ext", - &gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], - (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); - LOG_M("rxsigF0_comp.m","rxsF0_comp", - &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_ext.m","rxsF0_ext", + &gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chestF0.m","chF0", + &gNB->pusch_vars[0]->ul_ch_estimates[0][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1); + LOG_M("chestT0.m","chT0", + &gNB->pusch_vars[0]->ul_ch_estimates_time[0][0],frame_parms->ofdm_symbol_size,1,1); + LOG_M("chestF0_ext.m","chF0_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_comp.m","rxsF0_comp", + &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_M("chmagF0.m","chmF0", &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_M("chmagbF0.m","chmbF0", @@ -1454,48 +1422,47 @@ int main(int argc, char **argv) &gNB->pusch_vars[0]->llr_layers[2][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); LOG_M("rxsigF0_llrlayers3.m","rxsF0_llrlayers3", &gNB->pusch_vars[0]->llr_layers[3][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); - } + } - LOG_M("rxsigF0_llr.m","rxsF0_llr", - &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); - } + LOG_M("rxsigF0_llr.m","rxsF0_llr", + &gNB->pusch_vars[0]->llr[0],precod_nbr_layers*(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); + } //////////////////////////////////////////////////////////// - if ((gNB->ulsch[0]->last_iteration_cnt >= - gNB->ulsch[0]->max_ldpc_iterations+1) || ul_proc_error == 1) { - error_flag = 1; - n_errors[round][snrRun]++; - crc_status = 1; - } else { - crc_status = 0; - } - if(n_trials==1) printf("end of round %d rv_index %d\n",round, rv_index); + if ((gNB->ulsch[0]->last_iteration_cnt >= + gNB->ulsch[0]->max_ldpc_iterations+1) || ul_proc_error == 1) { + error_flag = 1; + n_errors[round][snrRun]++; + crc_status = 1; + } else + crc_status = 0; + if(n_trials==1) printf("end of round %d rv_index %d\n",round, rv_index); - //---------------------------------------------------------- - //----------------- count and print errors ----------------- - //---------------------------------------------------------- + //---------------------------------------------------------- + //----------------- count and print errors ----------------- + //---------------------------------------------------------- - if ((pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && (SNR==snr0) && (trial==0) && (round==0)) { - ptrs_symbols = 0; - for (int i = pusch_pdu->start_symbol_index; i < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; i++){ - ptrs_symbols += ((gNB->pusch_vars[UE_id]->ptrs_symbols) >> i) & 1; - } - /* 2*5*(50/2), for RB = 50,K = 2 for 5 OFDM PTRS symbols */ - available_bits -= 2 * ptrs_symbols * ((nb_rb + ptrs_freq_density - 1) /ptrs_freq_density); - printf("[ULSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5d \n",available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * 2) ); - } + if ((pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && (SNR==snr0) && (trial==0) && (round==0)) { + ptrs_symbols = 0; + for (int i = pusch_pdu->start_symbol_index; i < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; i++) + ptrs_symbols += ((gNB->pusch_vars[UE_id]->ptrs_symbols) >> i) & 1; - for (i = 0; i < available_bits; i++) { - - if(((ulsch_ue->harq_processes[harq_pid]->f[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) || - ((ulsch_ue->harq_processes[harq_pid]->f[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0))) - { - /*if(errors_scrambling == 0) - printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/ - errors_scrambling[round][snrRun]++; - } - } - round++; + /* 2*5*(50/2), for RB = 50,K = 2 for 5 OFDM PTRS symbols */ + available_bits -= 2 * ptrs_symbols * ((nb_rb + ptrs_freq_density - 1) /ptrs_freq_density); + printf("[ULSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5d \n",available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * 2) ); + } + + for (i = 0; i < available_bits; i++) { + + if(((ulsch_ue->harq_processes[harq_pid]->f[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) || + ((ulsch_ue->harq_processes[harq_pid]->f[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0))) { + + /*if(errors_scrambling == 0) + printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/ + errors_scrambling[round][snrRun]++; + } + } + round++; } // round From 05567b59f17e650d372c6e4c973d02f51a9e2ffa Mon Sep 17 00:00:00 2001 From: Vijay Chadachan Date: Tue, 26 Apr 2022 10:59:42 +0200 Subject: [PATCH 111/226] Fix for OAI UE AUTH_REQ processing additional check for RAND value It was observed in simulation test the OAI UE always sends the sucessful AUTH_RES when the AUTH_REQ has the RAND value "0". This opens a back door in the authentication process. The code is modified to fix this issue in OAI UE. --- openair3/NAS/UE/EMM/Authentication.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index 850f97150a..97c7082be0 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -149,7 +149,8 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, int rc = RETURNerror; authentication_data_t *authentication_data = user->authentication_data; emm_timers_t *emm_timers = user->emm_data->emm_timers; - + uint8_t nullRand[AUTH_CK_SIZE]; + memset(nullRand, 0, AUTH_CK_SIZE); LOG_TRACE(INFO, "EMM-PROC - Authentication requested ksi type = %s, ksi = %d", native_ksi ? "native" : "mapped", ksi); /* 3GPP TS 24.301, section 5.4.2.1 @@ -178,11 +179,13 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, OctetString ik = {AUTH_IK_SIZE, authentication_data->ik}; OctetString res = {AUTH_RES_SIZE, authentication_data->res}; - if (memcmp(authentication_data->rand, rand->value, AUTH_CK_SIZE) != 0) { + if ((memcmp(authentication_data->rand, rand->value, AUTH_CK_SIZE) != 0) || + (memcmp(nullRand,authentication_data->rand, AUTH_CK_SIZE) == 0)) { /* * There is no valid stored RAND in the ME or the stored RAND is * different from the new received value in the AUTHENTICATION - * REQUEST message + * REQUEST message OR the received RAND is all "0" or "NULL" + * process the new received AUTHENTICATIOn REQUEST message */ OctetString auts; auts.length = 0; From 8d2e5fd7aad1b35f8d07714da5bfc499d8e9b4c8 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 26 Apr 2022 11:53:32 +0200 Subject: [PATCH 112/226] fix(ci): CN5G does not keep PCAP in artifacts Signed-off-by: Raphael Defosseux --- ci-scripts/epc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 52583bb6d1..0e0afefaaf 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -539,7 +539,7 @@ class EPCManagement(): mySSH.command('python3 ./core-network.py '+self.cfgUnDeploy, '\$', 60) mySSH.command('docker volume prune --force || true', '\$', 60) time.sleep(2) - mySSH.command('tshark -r /tmp/oai-cn5g.pcap | egrep --colour=never "Tracking area update" ','\$', 30) + mySSH.command('tshark -r /tmp/oai-cn5g-v1.3.pcap | egrep --colour=never "Tracking area update" ','\$', 30) result = re.search('Tracking area update request', mySSH.getBefore()) if result is not None: message = 'UE requested ' + str(mySSH.getBefore().count('Tracking area update request')) + 'Tracking area update request(s)' @@ -833,8 +833,8 @@ class EPCManagement(): mySSH.command('zip mme.log.zip mme_check_run.*', '\$', 60) elif re.match('OAICN5G', self.Type, re.IGNORECASE): mySSH.command('cd ' + self.SourceCodePath + '/logs','\$', 5) - mySSH.command('cp -f /tmp/oai-cn5g.pcap .','\$', 30) - mySSH.command('zip mme.log.zip oai-amf.log oai-nrf.log oai-cn5g.pcap','\$', 30) + mySSH.command('cp -f /tmp/oai-cn5g-v1.3.pcap .','\$', 30) + mySSH.command('zip mme.log.zip oai-amf.log oai-nrf.log oai-cn5g*.pcap','\$', 30) mySSH.command('mv mme.log.zip ' + self.SourceCodePath + '/scripts','\$', 30) elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE): mySSH.command('zip mme.log.zip mme*.log', '\$', 60) From 5761f24eb064259316b6e7538d1de337421e7454 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 26 Apr 2022 13:58:39 +0200 Subject: [PATCH 113/226] fix(ci): 1st step to migrate the formatting / license check to the new pipeline env Signed-off-by: Raphael Defosseux --- ci-scripts/checkCodingFormattingRules.sh | 4 +- ci-scripts/cls_static_code_analysis.py | 50 +++++++++++++++++++ .../docker/Dockerfile.formatting.bionic | 25 ++++++++++ ci-scripts/main.py | 4 +- ci-scripts/xml_class_list.yml | 1 + ci-scripts/xml_files/formatting_check.xml | 37 ++++++++++++++ 6 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 ci-scripts/docker/Dockerfile.formatting.bionic create mode 100644 ci-scripts/xml_files/formatting_check.xml diff --git a/ci-scripts/checkCodingFormattingRules.sh b/ci-scripts/checkCodingFormattingRules.sh index a805f765df..c29941cade 100755 --- a/ci-scripts/checkCodingFormattingRules.sh +++ b/ci-scripts/checkCodingFormattingRules.sh @@ -59,7 +59,7 @@ if [ $# -eq 0 ] then echo " ---- Checking the whole repository ----" echo "" - NB_FILES_TO_FORMAT=`astyle --dry-run --options=ci-scripts/astyle-options.txt --recursive *.c *.h | grep -c Formatted || true` + NB_FILES_TO_FORMAT=`astyle --dry-run --options=ci-scripts/astyle-options.txt --recursive --exclude=ci-scripts --exclude=cmake_targets *.c *.h | grep -c Formatted || true` echo "Nb Files that do NOT follow OAI rules: $NB_FILES_TO_FORMAT" echo $NB_FILES_TO_FORMAT > ./oai_rules_result.txt @@ -136,7 +136,7 @@ fi # Merge request scenario MERGE_COMMMIT=`git log -n1 --pretty=format:%H` -TARGET_INIT_COMMIT=`cat .git/refs/remotes/origin/$TARGET_BRANCH` +TARGET_INIT_COMMIT=`git log -n1 --pretty=format:%H origin/$TARGET_BRANCH` echo " ---- Checking the modified files by the merge request ----" echo "" diff --git a/ci-scripts/cls_static_code_analysis.py b/ci-scripts/cls_static_code_analysis.py index d6796ad414..feea106190 100644 --- a/ci-scripts/cls_static_code_analysis.py +++ b/ci-scripts/cls_static_code_analysis.py @@ -237,3 +237,53 @@ class StaticCodeAnalysis(): return 0 + def LicenceAndFormattingCheck(self, HTML): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + logging.debug('Building on server: ' + lIpAddr) + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + + self.testCase_id = HTML.testCase_id + + # on RedHat/CentOS .git extension is mandatory + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) + if result is not None: + full_ran_repo_name = self.ranRepository.replace('git/', 'git') + else: + full_ran_repo_name = self.ranRepository + '.git' + mySSH.command('mkdir -p ' + lSourcePath, '\$', 5) + mySSH.command('cd ' + lSourcePath, '\$', 5) + mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) + # Raphael: here add a check if git clone or git fetch went smoothly + mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + mySSH.command('git config user.name "OAI Jenkins"', '\$', 5) + + mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + mySSH.command('mkdir -p cmake_targets/log', '\$', 5) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + + mySSH.command('docker image rm oai-formatting-check:latest || true', '\$', 60) + mySSH.command('docker build --target oai-formatting-check --tag oai-formatting-check:latest --file ci-scripts/docker/Dockerfile.formatting.bionic . > cmake_targets/log/oai-formatting-check.txt 2>&1', '\$', 600) + + return 0 diff --git a/ci-scripts/docker/Dockerfile.formatting.bionic b/ci-scripts/docker/Dockerfile.formatting.bionic new file mode 100644 index 0000000000..0f29c8b833 --- /dev/null +++ b/ci-scripts/docker/Dockerfile.formatting.bionic @@ -0,0 +1,25 @@ +FROM ubuntu:bionic AS oai-formatting-check + +ARG MERGE_REQUEST +ARG SRC_BRANCH +ARG TARGET_BRANCH +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + astyle \ + gawk \ + git + +WORKDIR /oai-ran +COPY . . + +RUN /bin/bash -c "if [[ -v MERGE_REQUEST ]]; then echo 'Source Branch = $SRC_BRANCH'; echo 'Target Branch = $TARGET_BRANCH'; else echo 'Push to develop'; fi" +RUN /bin/bash -c "if [[ -v MERGE_REQUEST ]]; then ./ci-scripts/checkCodingFormattingRules.sh --src-branch $SRC_BRANCH --target-branch $TARGET_BRANCH; else ./ci-scripts/checkCodingFormattingRules.sh; fi" && \ + ls -lst *.txt && \ + cat *.txt + +#RUN ./ci-scripts/checkCodingFormattingRules.sh && \ +# ls -lst *.txt +# diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 03947bdfc9..41577b0aa3 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -799,7 +799,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re HTML.startTime=int(round(time.time() * 1000)) while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.prematureExit: RAN.prematureExit=False - # At every iteratin of the retry loop, a separator will be added + # At every iteration of the retry loop, a separator will be added # pass CiTestObj.FailReportCnt as parameter of HTML.CreateHtmlRetrySeparator HTML.CreateHtmlRetrySeparator(CiTestObj.FailReportCnt) for test_case_id in todo_tests: @@ -923,6 +923,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re CONTAINERS.UndeployObject(HTML, RAN) elif action == 'Cppcheck_Analysis': SCA.CppCheckAnalysis(HTML) + elif action == 'LicenceAndFormattingCheck': + SCA.LicenceAndFormattingCheck(HTML) elif action == 'Deploy_Run_PhySim': PHYSIM.Deploy_PhySim(HTML, RAN) elif action == 'DeployGenObject': diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index d6f75191a8..b305aff424 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -47,3 +47,4 @@ - PingFromContainer - IperfFromContainer - StatsFromGenObject + - LicenceAndFormattingCheck diff --git a/ci-scripts/xml_files/formatting_check.xml b/ci-scripts/xml_files/formatting_check.xml new file mode 100644 index 0000000000..bdf47af65d --- /dev/null +++ b/ci-scripts/xml_files/formatting_check.xml @@ -0,0 +1,37 @@ + + + formatting-tab + License and Formatting Checks + wrench + + 000002 + + + + + LicenceAndFormattingCheck + License and Formatting Checks + + + From 275522eae3ba0a3bcedc83023537c109721e4103 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 26 Apr 2022 16:54:42 +0200 Subject: [PATCH 114/226] feat(ci): reporting in HTML of formatting and licences checks Signed-off-by: Raphael Defosseux --- ci-scripts/cls_static_code_analysis.py | 157 +++++++++++++++++- .../docker/Dockerfile.formatting.bionic | 18 +- ci-scripts/main.py | 4 +- 3 files changed, 170 insertions(+), 9 deletions(-) diff --git a/ci-scripts/cls_static_code_analysis.py b/ci-scripts/cls_static_code_analysis.py index feea106190..5b45b48ba6 100644 --- a/ci-scripts/cls_static_code_analysis.py +++ b/ci-scripts/cls_static_code_analysis.py @@ -37,6 +37,7 @@ import logging import os from pathlib import Path import time +from multiprocessing import Process, Lock, SimpleQueue #----------------------------------------------------------- # OAI Testing modules @@ -275,15 +276,167 @@ class StaticCodeAnalysis(): mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30) # if the branch is not develop, then it is a merge request and we need to do # the potential merge. Note that merge conflicts should already been checked earlier + argToPass = '' if (self.ranAllowMerge): + argToPass = '--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH=' + self.ranBranch if self.ranTargetBranch == '': if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + argToPass += ' --build-arg TARGET_BRANCH=develop ' else: logging.debug('Merging with the target branch: ' + self.ranTargetBranch) mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + argToPass += ' --build-arg TARGET_BRANCH=' + self.ranTargetBranch + ' ' mySSH.command('docker image rm oai-formatting-check:latest || true', '\$', 60) - mySSH.command('docker build --target oai-formatting-check --tag oai-formatting-check:latest --file ci-scripts/docker/Dockerfile.formatting.bionic . > cmake_targets/log/oai-formatting-check.txt 2>&1', '\$', 600) + mySSH.command('docker build --target oai-formatting-check --tag oai-formatting-check:latest ' + argToPass + '--file ci-scripts/docker/Dockerfile.formatting.bionic . > cmake_targets/log/oai-formatting-check.txt 2>&1', '\$', 600) - return 0 + mySSH.command('docker image rm oai-formatting-check:latest || true', '\$', 60) + mySSH.command('docker image prune --force', '\$', 60) + mySSH.command('docker volume prune --force', '\$', 60) + + # Analyzing the logs + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + mySSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) + mySSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) + mySSH.close() + + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/build_log_' + self.testCase_id + '/*', '.') + + finalStatus = 0 + if (os.path.isfile('./oai-formatting-check.txt')): + analyzed = False + nbFilesNotFormatted = 0 + listFiles = False + listFilesNotFormatted = [] + circularHeaderDependency = False + circularHeaderDependencyFiles = [] + gnuGplLicence = False + gnuGplLicenceFiles = [] + suspectLicence = False + suspectLicenceFiles = [] + with open('./oai-formatting-check.txt', 'r') as logfile: + for line in logfile: + ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line)) + if ret is not None: + analyzed = True + if analyzed: + ret = re.search('Nb Files that do NOT follow OAI rules: (?P[0-9\.]+)', str(line)) + if ret is not None: + nbFilesNotFormatted = int(ret.group('nb_errors')) + + if re.search('=== Files not properly formatted ===', str(line)) is not None: + listFiles = True + if listFiles: + if re.search('Removing intermediate container', str(line)) is not None: + listFiles = False + elif re.search('Running in|Files not properly formatted', str(line)) is not None: + pass + else: + listFilesNotFormatted.append(str(line).strip()) + + if re.search('=== Files with incorrect define protection ===', str(line)) is not None: + circularHeaderDependency = True + if circularHeaderDependency: + if re.search('Removing intermediate container', str(line)) is not None: + circularHeaderDependency = False + elif re.search('Running in|Files with incorrect define protection', str(line)) is not None: + pass + else: + circularHeaderDependencyFiles.append(str(line).strip()) + + if re.search('=== Files with a GNU GPL licence Banner ===', str(line)) is not None: + gnuGplLicence = True + if gnuGplLicence: + if re.search('Removing intermediate container', str(line)) is not None: + gnuGplLicence = False + elif re.search('Running in|Files with a GNU GPL licence Banner', str(line)) is not None: + pass + else: + gnuGplLicenceFiles.append(str(line).strip()) + + if re.search('=== Files with a suspect Banner ===', str(line)) is not None: + suspectLicence = True + if suspectLicence: + if re.search('Removing intermediate container', str(line)) is not None: + suspectLicence = False + elif re.search('Running in|Files with a suspect Banner', str(line)) is not None: + pass + else: + suspectLicenceFiles.append(str(line).strip()) + + logfile.close() + if analyzed: + logging.debug('files not formatted properly: ' + str(nbFilesNotFormatted)) + if nbFilesNotFormatted == 0: + HTML.CreateHtmlTestRow('File(s) Format', 'OK', CONST.ALL_PROCESSES_OK) + else: + html_queue = SimpleQueue() + html_cell = '
\n'
+					html_cell += 'Number of files not following OAI Rules: ' + str(nbFilesNotFormatted) + '\n'
+					for nFile in listFilesNotFormatted:
+						html_cell += str(nFile).strip() + '\n'
+					html_cell += '
' + html_queue.put(html_cell) + HTML.CreateHtmlTestRowQueue('File(s) Format', 'KO', 1, html_queue) + del(html_cell) + del(html_queue) + + logging.debug('header files not respecting the circular dependency protection: ' + str(len(circularHeaderDependencyFiles))) + if len(circularHeaderDependencyFiles) == 0: + HTML.CreateHtmlTestRow('Header Circular Dependency', 'OK', CONST.ALL_PROCESSES_OK) + else: + html_queue = SimpleQueue() + html_cell = '
\n'
+					html_cell += 'Number of files not respecting: ' + str(len(circularHeaderDependencyFiles)) + '\n'
+					for nFile in circularHeaderDependencyFiles:
+						html_cell += str(nFile).strip() + '\n'
+					html_cell += '
' + html_queue.put(html_cell) + HTML.CreateHtmlTestRowQueue('Header Circular Dependency', 'KO', 1, html_queue) + del(html_cell) + del(html_queue) + finalStatus = -1 + + logging.debug('files with a GNU GPL license: ' + str(len(gnuGplLicenceFiles))) + if len(gnuGplLicenceFiles) == 0: + HTML.CreateHtmlTestRow('Files w/ GNU GPL License', 'OK', CONST.ALL_PROCESSES_OK) + else: + html_queue = SimpleQueue() + html_cell = '
\n'
+					html_cell += 'Number of files not respecting: ' + str(len(gnuGplLicenceFiles)) + '\n'
+					for nFile in gnuGplLicenceFiles:
+						html_cell += str(nFile).strip() + '\n'
+					html_cell += '
' + html_queue.put(html_cell) + HTML.CreateHtmlTestRowQueue('Files w/ GNU GPL License', 'KO', 1, html_queue) + del(html_cell) + del(html_queue) + finalStatus = -1 + + logging.debug('files with a suspect license: ' + str(len(suspectLicenceFiles))) + if len(suspectLicenceFiles) == 0: + HTML.CreateHtmlTestRow('Files with suspect license', 'OK', CONST.ALL_PROCESSES_OK) + else: + html_queue = SimpleQueue() + html_cell = '
\n'
+					html_cell += 'Number of files not respecting: ' + str(len(suspectLicenceFiles)) + '\n'
+					for nFile in suspectLicenceFiles:
+						html_cell += str(nFile).strip() + '\n'
+					html_cell += '
' + html_queue.put(html_cell) + HTML.CreateHtmlTestRowQueue('Files with suspect license', 'KO', 1, html_queue) + del(html_cell) + del(html_queue) + finalStatus = -1 + + else: + finalStatus = -1 + HTML.htmleNBFailureMsg = 'Could not fully analyze oai-formatting-check.txt file' + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + else: + finalStatus = -1 + HTML.htmleNBFailureMsg = 'Could not access oai-formatting-check.txt file' + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + + return finalStatus diff --git a/ci-scripts/docker/Dockerfile.formatting.bionic b/ci-scripts/docker/Dockerfile.formatting.bionic index 0f29c8b833..01417a3bdb 100644 --- a/ci-scripts/docker/Dockerfile.formatting.bionic +++ b/ci-scripts/docker/Dockerfile.formatting.bionic @@ -16,10 +16,16 @@ WORKDIR /oai-ran COPY . . RUN /bin/bash -c "if [[ -v MERGE_REQUEST ]]; then echo 'Source Branch = $SRC_BRANCH'; echo 'Target Branch = $TARGET_BRANCH'; else echo 'Push to develop'; fi" -RUN /bin/bash -c "if [[ -v MERGE_REQUEST ]]; then ./ci-scripts/checkCodingFormattingRules.sh --src-branch $SRC_BRANCH --target-branch $TARGET_BRANCH; else ./ci-scripts/checkCodingFormattingRules.sh; fi" && \ - ls -lst *.txt && \ - cat *.txt +RUN /bin/bash -c "if [[ -v MERGE_REQUEST ]]; then ./ci-scripts/checkCodingFormattingRules.sh --src-branch $SRC_BRANCH --target-branch $TARGET_BRANCH; else ./ci-scripts/checkCodingFormattingRules.sh; fi" -#RUN ./ci-scripts/checkCodingFormattingRules.sh && \ -# ls -lst *.txt -# +RUN echo "=== Files not properly formatted ===" && \ + /bin/bash -c "if [[ -f oai_rules_result_list.txt ]]; then cat oai_rules_result_list.txt; fi" + +RUN echo "=== Files with incorrect define protection ===" && \ + /bin/bash -c "if [[ -f header-files-w-incorrect-define.txt ]]; then cat header-files-w-incorrect-define.txt; fi" + +RUN echo "=== Files with a GNU GPL licence Banner ===" && \ + /bin/bash -c "if [[ -f files-w-gnu-gpl-license-banner.txt ]]; then cat files-w-gnu-gpl-license-banner.txt; fi" + +RUN echo "=== Files with a suspect Banner ===" && \ + /bin/bash -c "if [[ -f files-w-suspect-banner.txt ]]; then cat files-w-suspect-banner.txt; fi" diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 41577b0aa3..adef885942 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -924,7 +924,9 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Cppcheck_Analysis': SCA.CppCheckAnalysis(HTML) elif action == 'LicenceAndFormattingCheck': - SCA.LicenceAndFormattingCheck(HTML) + ret = SCA.LicenceAndFormattingCheck(HTML) + if ret != 0: + RAN.prematureExit = True elif action == 'Deploy_Run_PhySim': PHYSIM.Deploy_PhySim(HTML, RAN) elif action == 'DeployGenObject': From b805e6db47bbb42dd97a735984e75860ddd8274e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Apr 2022 17:40:42 +0200 Subject: [PATCH 115/226] Use --continuous-tx for B210-based gNB (TDD) --- ci-scripts/xml_files/fr1_nsa_quectel.xml | 2 +- ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index 55f6f4376e..44aab6e892 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -74,7 +74,7 @@ Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E -q --RUs.[0].sdr_addrs "serial=30C51D4" --log_config.global_log_options level,nocolor,time,line_num,function + -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E -q --RUs.[0].sdr_addrs "serial=30C51D4" --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function 1 1 nr diff --git a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml index 61266aa2b1..208e1564cd 100644 --- a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml @@ -26,7 +26,7 @@ services: FLEXRAN_INTERFACE_NAME: eth0 FLEXRAN_IPV4_ADDRESS: 172.21.16.136 THREAD_PARALLEL_CONFIG: PARALLEL_RU_L1_TRX_SPLIT - USE_ADDITIONAL_OPTIONS: -E -q --RUs.[0].sdr_addrs serial=30C51D4 --log_config.global_log_options level,nocolor,time,line_num,function + USE_ADDITIONAL_OPTIONS: -E -q --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function volumes: - /dev:/dev networks: From 57d1b22ca4296ba3e92a990ad41432e895f83ceb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Apr 2022 17:48:23 +0200 Subject: [PATCH 116/226] Improve B210 gNB configuration --- .../conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index af58145322..f2bf69d2f7 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -203,7 +203,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; - ulsch_max_frame_inactivity = 1; + ulsch_max_frame_inactivity = 0; } ); @@ -221,11 +221,11 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 3 - att_rx = 0; + att_tx = 16 + att_rx = 16; bands = [7]; max_pdschReferenceSignalPower = -27; - max_rxgain = 111; + max_rxgain = 114; eNB_instances = [0]; # sdr_addrs = "serial=30C51D4"; # clock_src = "external"; From 4389fdea4ef82dba502271235ab65d5b446d5432 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Apr 2022 18:16:19 +0200 Subject: [PATCH 117/226] Harmonize NSA DMRS AdditionalPosition with SA --- openair2/RRC/NR/rrc_gNB_reconfig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 36113fb7ee..4e9245cf46 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -223,7 +223,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS=NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); - *secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos0; + *secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList)); @@ -572,7 +572,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS=NULL; } bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); - *bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos0; + *bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; bwp->bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList)); From 89e7923652c0f28ce1dd2538c3cb562ffc6dc962 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Apr 2022 17:56:50 +0200 Subject: [PATCH 118/226] Increase NSA B210 throughput requirements --- .../xml_files/container_nsa_b200_quectel.xml | 8 ++++---- ci-scripts/xml_files/fr1_nsa_quectel.xml | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 610f0b019a..80ed3f5cfc 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -138,12 +138,12 @@ Iperf - iperf (DL/40Mbps/UDP)(60 sec)(single-ue profile) - -u -b 40M -t 60 -i 1 -fm + iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) + -u -b 125M -t 60 -i 1 -fm DL idefix - 20 - 85 + 1 + 95 single-ue diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index 44aab6e892..f8ecaae0fd 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -117,29 +117,29 @@ -u -b 30M -t 30 DL idefix - 5 + 1 95 single-ue Iperf - iperf (DL/40Mbps/UDP)(30 sec)(single-ue profile) - -u -b 40M -t 30 + iperf (DL/90Mbps/UDP)(30 sec)(single-ue profile) + -u -b 90M -t 30 DL idefix - 5 + 1 95 single-ue Iperf - iperf (DL/60Mbps/UDP)(60 sec)(single-ue profile) - -u -b 60M -t 60 + iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) + -u -b 125M -t 60 DL idefix - 5 + 1 95 single-ue From cb456a23cc1f60de459d4184725dd64688ea12f0 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 26 Apr 2022 20:25:53 +0100 Subject: [PATCH 119/226] Fix in atxlev computation in ulsim (the loop should be over nb_antennas_tx and not nb_antennas_rx) and remove wrong sigma_dB computation --- openair1/SIMULATION/NR_PHY/ulsim.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 8b30958131..3d16eeaa2f 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1224,7 +1224,7 @@ int main(int argc, char **argv) //////////////////////////////////////////////////// tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); txlev_sum = 0; - for (int aa=0; aanb_antennas_rx; aa++) { + for (int aa=0; aanb_antennas_tx; aa++) { atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); @@ -1279,9 +1279,6 @@ int main(int argc, char **argv) r_im[ap][i] += s_im[aa][i]*H_awgn[ap][aa]; } } - - sigma_dB = 10 * log10((double)atxlev[ap] * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; - sigma = pow(10,sigma_dB/10); ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); From e168c0f33bbeafd3675561486adb9c73ad6454c8 Mon Sep 17 00:00:00 2001 From: Manish Date: Wed, 27 Apr 2022 05:31:12 +0000 Subject: [PATCH 120/226] help menu updated in document for native architecture. Compilation steps corrected on Ubuntu 20. Signed-off-by: Manish --- doc/BUILD.md | 1 + doc/TESTING_5GSA_setup.md | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index a52ce98cb5..70d69f5afd 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -193,6 +193,7 @@ Using the help option of the build script you can get the list of available opti | --UE | maintained and tested in CI | build `lte-uesoftmodem` the LTE UE | | --gNB | maintained and tested in CI | build `nr-softmodem` the 5G gNodeB | | --nrUE | maintained and tested in CI | build `nr-uesoftmodem` the 5G UE | +| --arch-native | maintained | build with native architecture optimization | | --usrp-recplay | deprecated | use the USRP configuration parameters to use the record player. | | --build-lib | maintained | build optional shared library(ies), which can then be loaded at run time via command line option. Use the --help option to get the list of supported optional libraries. `all` can be used to build all available optional libraries. | | --UE-conf-nvram | maintained | Specifies the path to the input file used by the conf2uedata utility. defaults to [openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf](../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf) | diff --git a/doc/TESTING_5GSA_setup.md b/doc/TESTING_5GSA_setup.md index 9b27549df4..4b86e12297 100644 --- a/doc/TESTING_5GSA_setup.md +++ b/doc/TESTING_5GSA_setup.md @@ -82,15 +82,7 @@ To get the code and build the gNB executable: git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git git checkout develop - # Install dependencies in Ubuntu 20.04 - cd - cd openairinterface5g/ - source oaienv - cd cmake_targets/ - ./install_external_packages.ubuntu20 - # Build OAI gNB - cd cd openairinterface5g/ source oaienv cd cmake_targets/ From 7e172e348bc279a2fc26474a3c8d984b7f82937f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 27 Apr 2022 11:51:29 +0100 Subject: [PATCH 121/226] Fix from frame_parms->nb_antennas_tx to UE->frame_parms.nb_antennas_tx in ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 3d16eeaa2f..6521324bec 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1224,7 +1224,7 @@ int main(int argc, char **argv) //////////////////////////////////////////////////// tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); txlev_sum = 0; - for (int aa=0; aanb_antennas_tx; aa++) { + for (int aa=0; aaframe_parms.nb_antennas_tx; aa++) { atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); From a4f3d431f5a52e876c26f61ea7159c039250b145 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Apr 2022 16:31:35 +0200 Subject: [PATCH 122/226] Further improve B210/NSA gNB configuration file --- ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index f2bf69d2f7..f3515d3882 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -221,8 +221,8 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 16 - att_rx = 16; + att_tx = 12 + att_rx = 12; bands = [7]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; From c265cbda8a272dd245dd7635cce12a70f62409e0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Apr 2022 16:36:16 +0200 Subject: [PATCH 123/226] NSA-B200(-Container) test: increase UL traffic requirements --- ci-scripts/xml_files/container_nsa_b200_quectel.xml | 4 ++-- ci-scripts/xml_files/fr1_nsa_quectel.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 80ed3f5cfc..47a939f63c 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -149,8 +149,8 @@ Iperf - iperf (UL/3Mbps/UDP)(60 sec)(single-ue profile) - -u -b 3M -t 60 -i 1 -fm + iperf (UL/8Mbps/UDP)(60 sec)(single-ue profile) + -u -b 8M -t 60 -i 1 -fm UL idefix 1 diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index f8ecaae0fd..0f8c90abdf 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -146,8 +146,8 @@ Iperf - iperf (UL/3Mbps/UDP)(60 sec)(single-ue profile) - -u -b 3M -t 60 + iperf (UL/8Mbps/UDP)(60 sec)(single-ue profile) + -u -b 8M -t 60 UL idefix 1 From 629b04dc80800af8ec7351a88e88547a126488ba Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 27 Apr 2022 15:25:43 +0200 Subject: [PATCH 124/226] fix(ci): typo when printing Signed-off-by: Raphael Defosseux --- ci-scripts/cls_log_mgt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/cls_log_mgt.py b/ci-scripts/cls_log_mgt.py index e29e9168b7..f1dbf6b8ec 100644 --- a/ci-scripts/cls_log_mgt.py +++ b/ci-scripts/cls_log_mgt.py @@ -81,11 +81,11 @@ class Log_Mgt: def LogRotation(self): doLoop = True nbDays = 14 - while doLoop and nbDays > 2: + while doLoop and nbDays > 1: used_space = self.__CheckUsedSpace() #avail space in target folder if used_space > 80 : logging.debug('\u001B[1;37;41m Used Disk (' + str(used_space) + '%) > 80%, on ' + self.Username+'@'+self.IPAddress + '\u001B[0m') - logging.debug('\u001B[1;37;41m Removing Artifacts older than ' + nbDays + ' days \u001B[0m') + logging.debug('\u001B[1;37;41m Removing Artifacts older than ' + str(nbDays) + ' days \u001B[0m') self.__RemoveOldest(nbDays) nbDays -= 1 else: From e98afec56753f15427c29866626dbeb3c6e7a914 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Apr 2022 17:40:53 +0200 Subject: [PATCH 125/226] NSA-2x2 test: improve gNB configuration --- .../gnb.band78.nsa_2x2.106PRB.usrpn310.conf | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf index e3bd49e7fc..fa7c190538 100644 --- a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf @@ -199,12 +199,12 @@ gNBs = ); MACRLCs = ( - { - num_cc = 1; - tr_s_preference = "local_L1"; - tr_n_preference = "local_RRC"; - ulsch_max_frame_inactivity = 1; - } +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + ulsch_max_frame_inactivity = 0; +} ); L1s = ( @@ -213,6 +213,7 @@ L1s = ( tr_n_preference = "local_mac"; thread_pool_size = 8; prach_dtx_threshold = 120; + pucch0_dtx_threshold = 80; } ); From 730fa472ae361b5e3e7ab973c5c763b0cd74c046 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Apr 2022 17:46:17 +0200 Subject: [PATCH 126/226] NSA-2x2 test: increase DL traffic requirements --- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index a4dcb58e8b..332af80d22 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -115,11 +115,11 @@ Iperf - iperf (DL/60Mbps/UDP)(60 sec)(single-ue profile) - -u -b 60M -t 60 + iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) + -u -b 125M -t 60 DL nrmodule2_quectel - 5 + 15 single-ue From b089469935673c3101db6eb26edc74290a2491d3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Apr 2022 18:15:46 +0200 Subject: [PATCH 127/226] Reduce nr_dlsim 256QAM MCS 27 test case to MCS 26, see #543 --- cmake_targets/autotests/test_case_list.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index ce1b9dcdf4..b55228bdc9 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1093,7 +1093,7 @@ (Test8: 217 PRB 100 PDSCH-PRBs 110 PDSCH-Offset), (Test9: 106 PRBs 50 PDSCH-PRBs MCS Index 27), (Test10: 106 PRBs 50 PDSCH-PRBs MCS Index 16), - (Test11: 106 MCS-TABLE 256 QAM MCS Index 27), + (Test11: 106 MCS-TABLE 256 QAM MCS Index 26), (Test12: HARQ test 25% TP 4 rounds), (Test13: HARQ test 33% TP 3 rounds), (Test14: HARQ test 50% TP 2 rounds), @@ -1121,7 +1121,7 @@ -n100 -R217 -a110 -s5 -b100 -n100 -e27 -s30 -n100 -e16 -s10 - -n100 -q1 -e27 -s30 + -n100 -q1 -e26 -s30 -n100 -s1 -t25 -n100 -s1 -t33 -n100 -s1 -t50 From ced2a66f6e57e3afd77a7d547f0fc32e96fb2eaf Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 27 Apr 2022 18:36:01 +0200 Subject: [PATCH 128/226] fix(ci): changing the Docker Hub account to push to Signed-off-by: Raphael Defosseux --- ci-scripts/Jenkinsfile-push-registry | 13 +++++--- ci-scripts/provideUniqueImageTag.py | 6 ++-- .../4g_rfsimulator_fdd_05MHz/README.md | 28 ++++++++-------- ci-scripts/yaml_files/5g_l2sim_tdd/README.md | 32 +++++++++---------- .../yaml_files/5g_rfsimulator/README.md | 28 ++++++++-------- 5 files changed, 52 insertions(+), 55 deletions(-) diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index f5847ff0aa..bc1a80ba61 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -26,6 +26,9 @@ def nodeExecutor = params.nodeExecutor // Name of the phone resource def ciServerResource = params.serverResource +// Docker Hub account to push to +def DH_Account = "oaisoftwarealliance" + pipeline { agent { label nodeExecutor @@ -66,11 +69,11 @@ pipeline { def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue"] sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" listOfImages.eachWithIndex { item, iindex -> - sh "docker image tag ${item}:develop ${DH_Username}/${item}:develop" - sh "docker image tag ${item}:develop ${DH_Username}/${item}:${WEEK_TAG}" - sh "docker push --quiet ${DH_Username}/${item}:${WEEK_TAG}" - sh "docker push --quiet ${DH_Username}/${item}:develop" - sh "docker rmi ${DH_Username}/${item}:${WEEK_TAG} ${DH_Username}/${item}:develop" + sh "docker image tag ${item}:develop ${DH_Account}/${item}:develop" + sh "docker image tag ${item}:develop ${DH_Account}/${item}:${WEEK_TAG}" + sh "docker push --quiet ${DH_Account}/${item}:${WEEK_TAG}" + sh "docker push --quiet ${DH_Account}/${item}:develop" + sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop" } sh "docker logout > /dev/null 2>&1" } diff --git a/ci-scripts/provideUniqueImageTag.py b/ci-scripts/provideUniqueImageTag.py index ee8306402f..88d51ca6f8 100644 --- a/ci-scripts/provideUniqueImageTag.py +++ b/ci-scripts/provideUniqueImageTag.py @@ -5,15 +5,15 @@ import subprocess import sys AUTH_SERVICE = 'registry.docker.io' -AUTH_SCOPE = 'repository:rdefosseoai/oai-enb:pull' +AUTH_SCOPE = 'repository:oaisoftwarealliance/oai-enb:pull' def main() -> None: args = _parse_args() - cmd = 'curl -fsSL "https://auth.docker.io/token?service=' + AUTH_SERVICE + '&scope=' + AUTH_SCOPE + '" | jq --raw-output ".token"' + cmd = 'curl -fsSL "https://auth.docker.io/token?service=' + AUTH_SERVICE + '&scope=' + AUTH_SCOPE + '" 2>/dev/null | jq --raw-output ".token"' token = subprocess.check_output(cmd, shell=True, universal_newlines=True) token = str(token).strip() - cmd = 'curl -fsSL -H "Authorization: Bearer ' + token + '" "https://index.docker.io/v2/rdefosseoai/oai-enb/tags/list" | jq .' + cmd = 'curl -fsSL -H "Authorization: Bearer ' + token + '" "https://index.docker.io/v2/oaisoftwarealliance/oai-enb/tags/list" 2>/dev/null | jq .' listOfTags = subprocess.check_output(cmd, shell=True, universal_newlines=True) foundTag = False diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md index be0d63838b..1a947d0389 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/README.md @@ -31,9 +31,7 @@ This page is only valid for an `Ubuntu18` host. # 1. Retrieving the images on Docker-Hub # -Currently the images are hosted under the user account `rdefosseoai`. - -This may change in the future. +Currently the images are hosted under the team account `oaisoftwarealliance`. They were previously hosted under the user account `rdefosseoai`. Once again you may need to log on [docker-hub](https://hub.docker.com/) if your organization has reached pulling limit as `anonymous`. @@ -49,13 +47,13 @@ Now pull images. ```bash $ docker pull cassandra:2.1 $ docker pull redis:6.0.5 -$ docker pull rdefosseoai/oai-hss:latest -$ docker pull rdefosseoai/magma-mme:latest -$ docker pull rdefosseoai/oai-spgwc:latest -$ docker pull rdefosseoai/oai-spgwu-tiny:latest +$ docker pull oaisoftwarealliance/oai-hss:latest +$ docker pull oaisoftwarealliance/magma-mme:latest +$ docker pull oaisoftwarealliance/oai-spgwc:latest +$ docker pull oaisoftwarealliance/oai-spgwu-tiny:latest -$ docker pull rdefosseoai/oai-enb:develop -$ docker pull rdefosseoai/oai-lte-ue:develop +$ docker pull oaisoftwarealliance/oai-enb:develop +$ docker pull oaisoftwarealliance/oai-lte-ue:develop ``` If the `redis` tag is not available, pick the newest available `6.0.x` tag at [Docker Hub Redis Tags](https://hub.docker.com/_/redis?tab=tags). @@ -63,13 +61,13 @@ If the `redis` tag is not available, pick the newest available `6.0.x` tag at [D And **re-tag** them for tutorials' docker-compose file to work. ```bash -$ docker image tag rdefosseoai/oai-spgwc:latest oai-spgwc:latest -$ docker image tag rdefosseoai/oai-hss:latest oai-hss:latest -$ docker image tag rdefosseoai/oai-spgwu-tiny:latest oai-spgwu-tiny:latest -$ docker image tag rdefosseoai/magma-mme:latest magma-mme:latest +$ docker image tag oaisoftwarealliance/oai-spgwc:latest oai-spgwc:latest +$ docker image tag oaisoftwarealliance/oai-hss:latest oai-hss:latest +$ docker image tag oaisoftwarealliance/oai-spgwu-tiny:latest oai-spgwu-tiny:latest +$ docker image tag oaisoftwarealliance/magma-mme:latest magma-mme:latest -$ docker image tag rdefosseoai/oai-enb:develop oai-enb:develop -$ docker image tag rdefosseoai/oai-lte-ue:develop oai-lte-ue:develop +$ docker image tag oaisoftwarealliance/oai-enb:develop oai-enb:develop +$ docker image tag oaisoftwarealliance/oai-lte-ue:develop oai-lte-ue:develop ``` ```bash diff --git a/ci-scripts/yaml_files/5g_l2sim_tdd/README.md b/ci-scripts/yaml_files/5g_l2sim_tdd/README.md index f1e1287995..c3f631cf76 100644 --- a/ci-scripts/yaml_files/5g_l2sim_tdd/README.md +++ b/ci-scripts/yaml_files/5g_l2sim_tdd/README.md @@ -18,9 +18,7 @@ This tutorial is only valid once this file is merged into the `develop` branch. # 1. Retrieving the images on Docker-Hub # -Currently the images are hosted under the user account `rdefosseoai`. - -This may change in the future. +Currently the images are hosted under the team account `oaisoftwarealliance`. They were previously hosted under the user account `rdefosseoai`. Once again you may need to log on [docker-hub](https://hub.docker.com/) if your organization has reached pulling limit as `anonymous`. @@ -35,27 +33,27 @@ Now pull images. ```bash $ docker pull mysql:5.7 -$ docker pull rdefosseoai/oai-amf:latest -$ docker pull rdefosseoai/oai-nrf:latest -$ docker pull rdefosseoai/oai-smf:latest -$ docker pull rdefosseoai/oai-spgwu-tiny:latest +$ docker pull oaisoftwarealliance/oai-amf:latest +$ docker pull oaisoftwarealliance/oai-nrf:latest +$ docker pull oaisoftwarealliance/oai-smf:latest +$ docker pull oaisoftwarealliance/oai-spgwu-tiny:latest -$ docker pull rdefosseoai/oai-gnb:develop -$ docker pull rdefosseoai/oai-nr-ue:develop -$ docker pull rdefosseoai/proxy:latest +$ docker pull oaisoftwarealliance/oai-gnb:develop +$ docker pull oaisoftwarealliance/oai-nr-ue:develop +$ docker pull oaisoftwarealliance/proxy:latest ``` And **re-tag** them for tutorials' docker-compose file to work. ```bash -$ docker image tag rdefosseoai/oai-amf:latest oai-amf:latest -$ docker image tag rdefosseoai/oai-nrf:latest oai-nrf:latest -$ docker image tag rdefosseoai/oai-smf:latest oai-smf:latest -$ docker image tag rdefosseoai/oai-spgwu-tiny:latest oai-spgwu-tiny:latest +$ docker image tag oaisoftwarealliance/oai-amf:latest oai-amf:latest +$ docker image tag oaisoftwarealliance/oai-nrf:latest oai-nrf:latest +$ docker image tag oaisoftwarealliance/oai-smf:latest oai-smf:latest +$ docker image tag oaisoftwarealliance/oai-spgwu-tiny:latest oai-spgwu-tiny:latest -$ docker image tag rdefosseoai/oai-gnb:develop oai-gnb:develop -$ docker image tag rdefosseoai/oai-nr-ue:develop oai-nr-ue:develop -$ docker image tag rdefosseoai/proxy:latest oai-lte-multi-ue-proxy:latest +$ docker image tag oaisoftwarealliance/oai-gnb:develop oai-gnb:develop +$ docker image tag oaisoftwarealliance/oai-nr-ue:develop oai-nr-ue:develop +$ docker image tag oaisoftwarealliance/proxy:latest oai-lte-multi-ue-proxy:latest ``` ```bash diff --git a/ci-scripts/yaml_files/5g_rfsimulator/README.md b/ci-scripts/yaml_files/5g_rfsimulator/README.md index 64c9084500..aa18571776 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/README.md +++ b/ci-scripts/yaml_files/5g_rfsimulator/README.md @@ -35,9 +35,7 @@ This page is only valid for an `Ubuntu18` host. # 1. Retrieving the images on Docker-Hub # -Currently the images are hosted under the user account `rdefosseoai`. - -This may change in the future. +Currently the images are hosted under the team account `oaisoftwarealliance`. They were previously hosted under the user account `rdefosseoai`. Once again you may need to log on [docker-hub](https://hub.docker.com/) if your organization has reached pulling limit as `anonymous`. @@ -52,25 +50,25 @@ Now pull images. ```bash $ docker pull mysql:5.7 -$ docker pull rdefosseoai/oai-amf:latest -$ docker pull rdefosseoai/oai-nrf:latest -$ docker pull rdefosseoai/oai-smf:latest -$ docker pull rdefosseoai/oai-spgwu-tiny:latest +$ docker pull oaisoftwarealliance/oai-amf:latest +$ docker pull oaisoftwarealliance/oai-nrf:latest +$ docker pull oaisoftwarealliance/oai-smf:latest +$ docker pull oaisoftwarealliance/oai-spgwu-tiny:latest -$ docker pull rdefosseoai/oai-gnb:develop -$ docker pull rdefosseoai/oai-nr-ue:develop +$ docker pull oaisoftwarealliance/oai-gnb:develop +$ docker pull oaisoftwarealliance/oai-nr-ue:develop ``` And **re-tag** them for tutorials' docker-compose file to work. ```bash -$ docker image tag rdefosseoai/oai-amf:latest oai-amf:latest -$ docker image tag rdefosseoai/oai-nrf:latest oai-nrf:latest -$ docker image tag rdefosseoai/oai-smf:latest oai-smf:latest -$ docker image tag rdefosseoai/oai-spgwu-tiny:latest oai-spgwu-tiny:latest +$ docker image tag oaisoftwarealliance/oai-amf:latest oai-amf:latest +$ docker image tag oaisoftwarealliance/oai-nrf:latest oai-nrf:latest +$ docker image tag oaisoftwarealliance/oai-smf:latest oai-smf:latest +$ docker image tag oaisoftwarealliance/oai-spgwu-tiny:latest oai-spgwu-tiny:latest -$ docker image tag rdefosseoai/oai-gnb:develop oai-gnb:develop -$ docker image tag rdefosseoai/oai-nr-ue:develop oai-nr-ue:develop +$ docker image tag oaisoftwarealliance/oai-gnb:develop oai-gnb:develop +$ docker image tag oaisoftwarealliance/oai-nr-ue:develop oai-nr-ue:develop ``` ```bash From e946ddbe47e4f1a22fbcfda5604e5fda3a00fbdc Mon Sep 17 00:00:00 2001 From: Eurecom Date: Wed, 27 Apr 2022 21:34:06 +0200 Subject: [PATCH 129/226] bugfix in if5_tools.c --- openair1/PHY/LTE_TRANSPORT/if5_tools.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index e71b1e31f6..76d62f34a2 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -1052,7 +1052,7 @@ static inline int64_t clock_difftime_ns(struct timespec start, struct timespec e void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seqno, uint16_t packet_type) { LTE_DL_FRAME_PARMS *fp=ru->frame_parms; - int32_t *txp[fp->nb_antennas_tx], *rxp[fp->nb_antennas_rx]; + int32_t *txp[ru->nb_tx], *rxp[ru->nb_rx]; int32_t *tx_buffer=NULL; uint16_t packet_id=0, i=0; @@ -1131,6 +1131,7 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seq //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id ); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 ); clock_gettime( CLOCK_MONOTONIC, &start_comp); + ru->ifdevice.trx_write_func2(&ru->ifdevice, (proc_timestamp + packet_id*spp_eth-600)*factor, (void*)txp[aid], From 8d43b9c4770b64b47f9f1fc89bf923e630c4741c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Apr 2022 09:47:05 +0200 Subject: [PATCH 130/226] NSA 2x2: Set bitrate threshold to mark test green (setup problem) --- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index 332af80d22..2ef2b7d7ce 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -120,6 +120,7 @@ DL nrmodule2_quectel 15 + 85 single-ue From 4df04fc48ca599901bd54e43478cc555955c37ef Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 11 Apr 2022 12:55:34 +0100 Subject: [PATCH 131/226] Avoid gNB to exit when UE release or becomes out of coverage --- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index baae1fa436..0a8e03fc1e 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -385,7 +385,6 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, rb->recv_sdu(rb, (char *)sdu_pP->data, sdu_sizeP, muiP); } else { LOG_E(RLC, "%s:%d:%s: fatal: SDU sent to unknown RB\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); } nr_rlc_manager_unlock(nr_rlc_ue_manager); From dda9077708ef7197d71c15e993ad976d71098b3c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 26 Apr 2022 09:46:11 +0100 Subject: [PATCH 132/226] Remove all GTPU tunnels for a specific RNTI after UEContextRelease --- openair2/RRC/NR/rrc_gNB.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1715677c6d..35c7b487d3 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3481,6 +3481,7 @@ void nr_rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { mac_remove_nr_ue(ctxt_pP->module_id, ctxt_pP->rnti); rrc_rlc_remove_ue(ctxt_pP); pdcp_remove_UE(ctxt_pP); + newGtpuDeleteAllTunnels(ctxt_pP->instance, ctxt_pP->rnti); /* remove RRC UE Context */ ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[ctxt_pP->module_id], ctxt_pP->rnti); From 3bdc709243142929545d334d3253b089aefbdde2 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 26 Apr 2022 18:37:25 +0100 Subject: [PATCH 133/226] Fix build of phy_simulators --- openair1/SIMULATION/NR_PHY/dlsim.c | 4 ++++ openair1/SIMULATION/NR_PHY/prachsim.c | 4 ++++ openair1/SIMULATION/NR_PHY/ulsim.c | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 00262149c9..eff65fa606 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -105,6 +105,10 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer return 0; } +int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { + return 0; +} + // dummy functions int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index f255ab5337..325cbb1ecc 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -97,6 +97,10 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer return 0; } +int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { + return 0; +} + void rrc_data_ind( const protocol_ctxt_t *const ctxt_pP, diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 09499248b2..e70d08bdb3 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -100,6 +100,11 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) { return 0; } + +int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { + return 0; +} + extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, From 264599a071d69a3f653fb2573e466c4c93619f55 Mon Sep 17 00:00:00 2001 From: hardy Date: Thu, 28 Apr 2022 11:16:19 +0200 Subject: [PATCH 134/226] update AS UE IP address after IT migration --- ci-scripts/ci_ueinfra.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index b888f6bb59..51fc4a264e 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -55,7 +55,7 @@ amarisoft_ue_1: Duration : 60 Ping : /tmp/test_ue1.log UELog : /tmp/ue1.log - HostIPAddress : 192.168.18.89 + HostIPAddress : 172.21.16.144 HostUsername : root HostPassword : toor HostSourceCodePath : /tmp From 6af3d0a3641907961b0676262fd99407deeec208 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 28 Apr 2022 11:27:27 +0200 Subject: [PATCH 135/226] change in ulsim test to show degradation in performances for 2rx scenario --- cmake_targets/autotests/test_case_list.xml | 4 ++-- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 5687810e69..4f564b9dd8 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1306,7 +1306,7 @@ (Test12: SC-FDMA, 216 PRBs), (Test13: SC-FDMA, 273 PRBs), (Test14: SC-FDMA, 3 DMRS), - (Test15: MCS 16 50 PRBs 2 RX_Antenna) + (Test15: MCS 19 50 PRBs 2 RX_Antenna) (Test16: MCS 9 106 PRBs MIMO 2 layers) (Test17: MCS 9 106 PRBs MIMO 4 layers) @@ -1329,7 +1329,7 @@ -n50 -s5 -Z -r216 -R217 -n50 -s5 -Z -r270 -R273 -n100 -s5 -Z -U 2 0 2 - -n100 -m16 -s10 -z2 + -n100 -m19 -s10 -S15 -z2 -n100 -m9 -r106 -s10 -W2 -y2 -z2 -n100 -m9 -r106 -s13 -W4 -y4 -z4 diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 3d16eeaa2f..6521324bec 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1224,7 +1224,7 @@ int main(int argc, char **argv) //////////////////////////////////////////////////// tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); txlev_sum = 0; - for (int aa=0; aanb_antennas_tx; aa++) { + for (int aa=0; aaframe_parms.nb_antennas_tx; aa++) { atxlev[aa] = signal_energy(&UE->common_vars.txdata[aa][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); From 99fde7f7cb09c2300e52da699725dff1830dfb4e Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 11:50:27 +0100 Subject: [PATCH 136/226] Fix some needed debug logs considering the multi-layer case --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index db05e03d4c..16c58210e4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -616,22 +616,21 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, #ifdef DEBUG_CH_COMP int16_t *rxF, *ul_ch; int prnt_idx; + for (int nl=0; nlnb_antennas_rx; aarx++) { + rxF = (int16_t *) &rxdataF_ext[aarx][symbol * (off + (nb_rb * 12))]; + ul_ch = (int16_t *) &ul_ch_estimates_ext[nl * frame_parms->nb_antennas_rx + aarx][symbol * (off + (nb_rb * 12))]; - for (int ant=0; antnb_antennas_rx; ant++) { - rxF = (int16_t *)&rxdataF_ext[ant][symbol*(off+(nb_rb*12))]; - ul_ch = (int16_t *)&ul_ch_estimates_ext[ant][symbol*(off+(nb_rb*12))]; - - printf("--------------------symbol = %d, mod_order = %d, output_shift = %d-----------------------\n", symbol, mod_order, output_shift); - printf("----------------Before compensation------------------\n"); - - for (prnt_idx=0;prnt_idx<12*5*2;prnt_idx+=2){ - - printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); - printf("ul_ch[%d] = (%d,%d)\n", prnt_idx>>1, ul_ch[prnt_idx],ul_ch[prnt_idx+1]); + printf("--------symbol = %d, mod_order = %d, output_shift = %d, layer %i, antenna rx = %d -----------\n", + symbol, mod_order, output_shift, nl, aarx); + printf("----------------Before compensation------------------\n"); + for (prnt_idx = 0; prnt_idx < 12 * 5 * 2; prnt_idx += 2) { + printf("rxF[%d] = (%d,%d)\n", prnt_idx >> 1, rxF[prnt_idx], rxF[prnt_idx + 1]); + printf("ul_ch[%d] = (%d,%d)\n", prnt_idx >> 1, ul_ch[prnt_idx], ul_ch[prnt_idx + 1]); + } } } - #endif #ifdef DEBUG_CH_MAG @@ -1137,19 +1136,17 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, #ifdef DEBUG_CH_COMP + for (int nl2=0; nl2nb_antennas_rx; aarx2++) { + rxF = (int16_t *)&rxdataF_comp[nl2*frame_parms->nb_antennas_rx+aarx2][(symbol*(off+(nb_rb*12)))]; - for (int ant=0; antnb_antennas_rx; ant++) { - rxF = (int16_t *)&rxdataF_comp[ant][(symbol*(off+(nb_rb*12)))]; - - printf("----------------After compansation------------------\n"); - - for (prnt_idx=0;prnt_idx<12*5*2;prnt_idx+=2){ - - printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); + printf("--------After compansation, layer %i, antenna rx %i----------\n", nl2, aarx2); + for (prnt_idx=0;prnt_idx<12*5*2;prnt_idx+=2){ + printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); + } } } - #endif #ifdef DEBUG_CH_MAG From 3571769bef1384596e8dd446e5bd851abf84c7c0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 11 Apr 2022 18:22:10 +0200 Subject: [PATCH 137/226] Correctly initialize RLC when using phy-test mode When using phy-test mode, the RNTI for PDCP/RLC initialization would be 0, incorrectly initializing these layers, fixed in this commit. Additionally, in this commit, we only trigger the initialization in cases where the UE context is initialized (before, the RNTI might be 0 in other cases as well). --- openair2/RRC/NR/rrc_gNB_nsa.c | 47 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index bb66d1513b..3f41c69d72 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -339,8 +339,6 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ sizeof(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer)); X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3; itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding - } else if (get_softmodem_params()->do_ra || get_softmodem_params()->sa) { - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_id_rnti, 0, 0,rrc->module_id); } rrc->Nb_ue++; @@ -374,36 +372,37 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ } if(m == NULL){ + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_id_rnti, 0, 0, rrc->module_id); LOG_W(RRC, "Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %x, frame %d, subframe %d eNB_index %d \n", &ctxt, ctxt.module_id, ctxt.rnti, ctxt.frame, ctxt.subframe, ctxt.eNB_index); + + nr_rrc_pdcp_config_asn1_req(&ctxt, + get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, + ue_context_p->ue_context.rb_config->drb_ToAddModList , + ue_context_p->ue_context.rb_config->drb_ToReleaseList, + (ue_context_p->ue_context.integrity_algorithm << 4) | ue_context_p->ue_context.ciphering_algorithm, + NULL, /* kRRCenc - unused */ + NULL, /* kRRCint - unused */ + kUPenc, /* kUPenc */ + kUPint, /* kUPint */ + NULL, + NULL, + ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); + + nr_rrc_rlc_config_asn1_req (&ctxt, + get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, + ue_context_p->ue_context.rb_config->drb_ToAddModList, + ue_context_p->ue_context.rb_config->drb_ToReleaseList, + (LTE_PMCH_InfoList_r9_t *) NULL, + ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); + + LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti); } - nr_rrc_pdcp_config_asn1_req(&ctxt, - get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, - ue_context_p->ue_context.rb_config->drb_ToAddModList , - ue_context_p->ue_context.rb_config->drb_ToReleaseList, - (ue_context_p->ue_context.integrity_algorithm << 4) | ue_context_p->ue_context.ciphering_algorithm, - NULL, /* kRRCenc - unused */ - NULL, /* kRRCint - unused */ - kUPenc, /* kUPenc */ - kUPint, /* kUPint */ - NULL, - NULL, - ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); - - nr_rrc_rlc_config_asn1_req (&ctxt, - get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, - ue_context_p->ue_context.rb_config->drb_ToAddModList, - ue_context_p->ue_context.rb_config->drb_ToReleaseList, - (LTE_PMCH_InfoList_r9_t *) NULL, - ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); - - LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti); - } void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) { From e4e08925ecb621af0a85ec24f039efdad8103a44 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Apr 2022 18:25:41 +0200 Subject: [PATCH 138/226] Speed up random TB filling in phy-test mode --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 53485886c0..03b35a17a5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1478,6 +1478,10 @@ void nr_schedule_ue_spec(module_id_t module_id, header->L = htons(bufEnd-buf); dlsch_total_bytes += bufEnd-buf; + for (; buf < bufEnd - 3; buf += 4) { + uint32_t *buf32 = (uint32_t *)buf; + *buf32 = lrand48(); + } for (; buf < bufEnd; buf++) *buf = lrand48() & 0xff; } From 3054102200af4ad66589eccd8d568b66cbfbe2c2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 13 Apr 2022 17:51:05 +0200 Subject: [PATCH 139/226] targets config file cleanup --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 3 --- targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - .../CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 2 +- .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - 7 files changed, 1 insertion(+), 9 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..6aacd98c7f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -45,10 +45,7 @@ gNBs = remote_s_portc = 500; remote_s_portd = 2152; ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 256d724f3f..f95bdf91ae 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -38,7 +38,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 726e43d7ad..f91683897f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -37,7 +37,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - sib1_tda = 0; + servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 7e2db64aaa..d124c5692f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..ff64fe718a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -36,7 +36,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 950e9c1d38..1bc6de3bfe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -35,7 +35,6 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; - sib1_tda = 0; do_SRS = 1; ul_prbblacklist = "51,52,53,54" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1dc903b811..a0cee6f9ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { From 40b0ce997835a37e4a5f404689d201fa0b661580 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 19 Apr 2022 15:47:12 +0200 Subject: [PATCH 140/226] vrb map fixes --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 9a651293b2..ede66f4b38 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -391,7 +391,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP const int16_t N_RA_RB = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); uint16_t *vrb_map_UL = &cc->vrb_map_UL[slotP * MAX_BWP_SIZE]; for (int i = 0; i < N_RA_RB * fdm; ++i) - vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] = SL_to_bitmap(start_symbol, N_t_slot*N_dur); + vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] |= SL_to_bitmap(start_symbol, N_t_slot*N_dur); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 4b654e2ad1..f631f9bfd5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -426,7 +426,7 @@ uint32_t schedule_control_sib1(module_id_t module_id, gNB_mac->sched_ctrlCommon->cce_index, gNB_mac->sched_ctrlCommon->aggregation_level); for (int rb = 0; rb < gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize; rb++) { - vrb_map[rb + rbStart] = SL_to_bitmap(startSymbolIndex, nrOfSymbols); + vrb_map[rb + rbStart] |= SL_to_bitmap(startSymbolIndex, nrOfSymbols); } return TBS; } From 4be054b8ba201be69542a8b23ec191b3728cf4fa Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 19 Apr 2022 17:24:48 +0200 Subject: [PATCH 141/226] Fix band66 CI config file locationAndBandwidth --- .../conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf index e26fc3030d..b78ca916f3 100644 --- a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -63,8 +63,8 @@ gNBs = dl_carrierBandwidth = 106; #initialDownlinkBWP #genericParameters - # this is RBstart=27,L=48 (275*(L-1))+RBstart - initialDLBWPlocationAndBandwidth = 13475; # 6366 12925 12956 28875 12952 + # this is RBstart=0,L=106 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialDLBWPsubcarrierSpacing = 1; @@ -85,7 +85,7 @@ gNBs = pMax = 20; #initialUplinkBWP #genericParameters - initialULBWPlocationAndBandwidth = 13475; + initialULBWPlocationAndBandwidth = 28875; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialULBWPsubcarrierSpacing = 1; From 1060de4c323aa774060f62ae504925ea0f09be10 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 20 Apr 2022 12:29:16 +0200 Subject: [PATCH 142/226] Correct frame calculation in UL scheduler --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 72061bb9ba..0d61c639ed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1479,7 +1479,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t if (tda < 0) return false; int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, tda, mu); - const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); + const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) % 1024; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) From db0a9f60c1990d90e7bcfafc2bbd3abe2dd9d0d3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 20 Apr 2022 12:32:24 +0200 Subject: [PATCH 143/226] Correct slot calculation in nr_acknack_scheduling() --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 43822d0cd0..0e87af56f5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1598,11 +1598,11 @@ int nr_acknack_scheduling(int mod_id, const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; // initializing the values for FDD int nr_slots_period = n_slots_frame; - int first_ul_slot_tdd = slot + minfbtime; + int next_ul_slot = slot + minfbtime; int first_ul_slot_period = 0; if(tdd){ nr_slots_period /= get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - first_ul_slot_tdd = tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period); + next_ul_slot = tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period); first_ul_slot_period = tdd->nrofDownlinkSlots; } else @@ -1746,8 +1746,8 @@ int nr_acknack_scheduling(int mod_id, AssertFatal(pucch->sr_flag + pucch->dai_c == 0, "expected no SR/AckNack for UE %d in %4d.%2d, but has %d/%d for %4d.%2d\n", UE_id, frame, slot, pucch->sr_flag, pucch->dai_c, pucch->frame, pucch->ul_slot); - const int s = first_ul_slot_tdd; - pucch->frame = (s < n_slots_frame - 1) ? frame : (frame + 1) % 1024; + const int s = next_ul_slot; + pucch->frame = s < n_slots_frame ? frame : (frame + 1) % 1024; pucch->ul_slot = s % n_slots_frame; } From 9fcc94313c17f42fb0e87c2875e47750e4bfd5dc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 21 Apr 2022 15:51:10 +0200 Subject: [PATCH 144/226] Make variables in nr_acknack_scheduling() const --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 0e87af56f5..bf9ca4d26d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1596,18 +1596,10 @@ int nr_acknack_scheduling(int mod_id, const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[CC_id].ServingCellConfigCommon; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - // initializing the values for FDD - int nr_slots_period = n_slots_frame; - int next_ul_slot = slot + minfbtime; - int first_ul_slot_period = 0; - if(tdd){ - nr_slots_period /= get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - next_ul_slot = tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period); - first_ul_slot_period = tdd->nrofDownlinkSlots; - } - else - // if TDD configuration is not present and the band is not FDD, it means it is a dynamic TDD configuration - AssertFatal(RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD,"Dynamic TDD not handled yet\n"); + AssertFatal(tdd || RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD, "Dynamic TDD not handled yet\n"); + const int nr_slots_period = tdd ? n_slots_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : n_slots_frame; + const int next_ul_slot = tdd ? tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period) : slot + minfbtime; + const int first_ul_slot_period = tdd ? tdd->nrofDownlinkSlots : 0; NR_sched_pucch_t *csi_pucch; From d5419a27f2ab14f3d93354bcd46ccb37fe05c333 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 21 Apr 2022 16:38:06 +0200 Subject: [PATCH 145/226] Correct check for free symbols for PUSCH/PDSCH allocation --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 19 ++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 26 +++++++++---------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 03b35a17a5..4dd098162c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -571,8 +571,8 @@ bool allocate_dl_retransmission(module_id_t module_id, rbStart += rbSize; /* last iteration rbSize was not enough, skip it */ rbSize = 0; - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols))) + const int slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; if (rbStart >= bwpSize) { @@ -581,7 +581,7 @@ bool allocate_dl_retransmission(module_id_t module_id, } while (rbStart + rbSize < bwpSize && - (rballoc_mask[rbStart + rbSize]&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols)) && + (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap && rbSize < retInfo->rbSize) rbSize++; } @@ -614,12 +614,11 @@ bool allocate_dl_retransmission(module_id_t module_id, ps->nrOfLayers, sched_ctrl, &temp_ps); - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) + const uint16_t slbitmap = SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; - while (rbStart + rbSize < bwpSize && - (rballoc_mask[rbStart + rbSize]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) + while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap) rbSize++; uint32_t new_tbs; @@ -929,14 +928,12 @@ void pf_dl(module_id_t module_id, const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); // Freq-demain allocation - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&slbitmap)) + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize < bwpSize && - (rballoc_mask[rbStart + max_rbSize]&slbitmap)) + while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) max_rbSize++; sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 0d61c639ed..e62ac993b4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1002,8 +1002,8 @@ bool allocate_ul_retransmission(module_id_t module_id, } /* Check the resource is enough for retransmission */ - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols))) + const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; if (rbStart + retInfo->rbSize > bwpSize) { LOG_W(NR_MAC, "cannot allocate retransmission of UE %d/RNTI %04x: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d\n", UE_id, UE_info->rnti[UE_id], rbStart, retInfo->rbSize, bwpSize); @@ -1023,12 +1023,11 @@ bool allocate_ul_retransmission(module_id_t module_id, &temp_ps); /* the retransmission will use a different time domain allocation, check * that we have enough resources */ - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) + const uint16_t slbitmap = SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; int rbSize = 0; - while (rbStart + rbSize < bwpSize && - (rballoc_mask[rbStart + rbSize]&SL_to_bitmap(temp_ps.startSymbolIndex, temp_ps.nrOfSymbols))) + while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap) rbSize++; uint32_t new_tbs; uint16_t new_rbSize; @@ -1260,8 +1259,8 @@ void pf_ul(module_id_t module_id, } LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d\n", min_rb, rbStart); - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols))) + const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; if (rbStart + min_rb >= bwpSize) { LOG_W(NR_MAC, "cannot allocate continuous UL data for UE %d/RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d\n", @@ -1294,7 +1293,7 @@ void pf_ul(module_id_t module_id, /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap; continue; } @@ -1398,13 +1397,12 @@ void pf_ul(module_id_t module_id, } update_ul_ue_R_Qm(sched_pusch, ps); - while (rbStart < bwpSize && - !(rballoc_mask[rbStart]&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols))) + const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; sched_pusch->rbStart = rbStart; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize < bwpSize && - (rballoc_mask[rbStart + max_rbSize]&&SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols))) + while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) max_rbSize++; if (rbStart + min_rb >= bwpSize) { @@ -1445,7 +1443,7 @@ void pf_ul(module_id_t module_id, n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap; } } From 00609ed15a8f52332e78783b34f1fb16e73000a4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 21 Apr 2022 17:11:02 +0200 Subject: [PATCH 146/226] Enable UDP traffic test in 5G FDD RFsim test --- ci-scripts/xml_files/container_5g_fdd_rfsim.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index 61a2af9e54..b41dafb767 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -33,12 +33,10 @@ 000013 020011 020012 - 100011 - - + 100011 + @@ -104,7 +102,7 @@ rfsim5g-oai-ext-dn rfsim5g-oai-nr-ue -u -i 1 -s - -B 12.1.1.2 -c 192.168.72.135 -u -i 1 -t 30 -b 1M + -B 12.1.1.2 -c 192.168.72.135 -u -i 1 -t 30 -b 3M From 85eb5926dd6d6c3446cf9a823ad71ddf9a85fc7f Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Thu, 28 Apr 2022 14:36:03 +0200 Subject: [PATCH 147/226] x2 nsa bug --- ci-scripts/ran.py | 72 +++++++++++++++-------------------- openair2/X2AP/x2ap_eNB.c | 19 ++++----- openair3/SCTP/sctp_common.h | 2 +- openair3/SCTP/sctp_eNB_task.c | 18 ++++----- 4 files changed, 45 insertions(+), 66 deletions(-) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 287a0a3c09..97c5b9696e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -372,36 +372,28 @@ class RANManagement(): else: pcapfile_prefix="gnb_" mySSH.open(lIpAddr, lUserName, lPassWord) - mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', mySSH.getBefore()) - if result is not None: - eth_interface = result.group('eth_interface') - fltr = 'port 38412 or port 36412 or port 36422' # NGAP, S1AP, X2AP - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') - pcapfile = pcapfile_prefix + self.testCase_id + '_log.pcap' - mySSH.command('echo ' + lPassWord + ' | sudo -S rm -f /tmp/' + pcapfile , '\$', 5) - mySSH.command('echo $USER; nohup sudo -E tshark -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + pcapfile + ' > /dev/null 2>&1 &','\$', 5) + eth_interface = 'any' + fltr = 'sctp' + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') + pcapfile = pcapfile_prefix + self.testCase_id + '_log.pcap' + mySSH.command('echo ' + lPassWord + ' | sudo -S rm -f /tmp/' + pcapfile , '\$', 5) + mySSH.command('echo $USER; nohup sudo -E tshark -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + pcapfile + ' > /dev/null 2>&1 &','\$', 5) mySSH.close() # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if (result is not None): - localEpcIpAddr = EPC.IPAddress - localEpcUserName = EPC.UserName - localEpcPassword = EPC.Password - mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) - mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', mySSH.getBefore()) - if result is not None: - eth_interface = result.group('eth_interface') - fltr = 'port 38412 or port 36412 or port 36422' # NGAP, S1AP, X2AP - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') - self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' - mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) - mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) - mySSH.close() + localEpcIpAddr = EPC.IPAddress + localEpcUserName = EPC.UserName + localEpcPassword = EPC.Password + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) + eth_interface = 'any' + fltr = 'sctp' + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') + self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' + mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) + mySSH.close() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath, '\$', 5) # Initialize_eNB_args usually start with -O and followed by the location in repository @@ -519,23 +511,19 @@ class RANManagement(): logging.error('\u001B[1;37;41m eNB/gNB/ocp-eNB logging system did not show got sync! \u001B[0m') HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK) # In case of T tracer recording, we need to kill tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if (result is not None): - localEpcIpAddr = EPC.IPAddress - localEpcUserName = EPC.UserName - localEpcPassword = EPC.Password - mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if self.epcPcapFile != '': - time.sleep(0.5) - mySSH.command('echo ' + localEpcPassword + ' | sudo -S chmod 666 /tmp/' + self.epcPcapFile, '\$', 5) - mySSH.close() - time.sleep(1) - if self.epcPcapFile != '': - copyin_res = mySSH.copyin(localEpcIpAddr, localEpcUserName, localEpcPassword, '/tmp/' + self.epcPcapFile, '.') - if (copyin_res == 0): - mySSH.copyout(lIpAddr, lUserName, lPassWord, self.epcPcapFile, lSourcePath + '/cmake_targets/.') + localEpcIpAddr = EPC.IPAddress + localEpcUserName = EPC.UserName + localEpcPassword = EPC.Password + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if self.epcPcapFile != '': + mySSH.command('echo ' + localEpcPassword + ' | sudo -S chmod 666 /tmp/' + self.epcPcapFile, '\$', 5) + mySSH.close() + if self.epcPcapFile != '': + copyin_res = mySSH.copyin(localEpcIpAddr, localEpcUserName, localEpcPassword, '/tmp/' + self.epcPcapFile, '.') + if (copyin_res == 0): + mySSH.copyout(lIpAddr, lUserName, lPassWord, self.epcPcapFile, lSourcePath + '/cmake_targets/.') self.prematureExit = True return else: diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c index 2b1d19001a..a73bc0a640 100644 --- a/openair2/X2AP/x2ap_eNB.c +++ b/openair2/X2AP/x2ap_eNB.c @@ -70,8 +70,7 @@ void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p, net_ip_address_t *local_ip_addr, uint16_t in_streams, uint16_t out_streams, - uint32_t enb_port_for_X2C, - int multi_sd); + uint32_t enb_port_for_X2C); static void x2ap_eNB_handle_handover_req(instance_t instance, @@ -249,20 +248,17 @@ static void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p, net_ip_address_t *local_ip_addr, uint16_t in_streams, uint16_t out_streams, - uint32_t enb_port_for_X2C, - int multi_sd) { + uint32_t enb_port_for_X2C) { MessageDef *message = NULL; - sctp_new_association_req_multi_t *sctp_new_association_req = NULL; x2ap_eNB_data_t *x2ap_enb_data = NULL; DevAssert(instance_p != NULL); DevAssert(target_eNB_ip_address != NULL); - message = itti_alloc_new_message(TASK_X2AP, 0, SCTP_NEW_ASSOCIATION_REQ_MULTI); - sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi; + message = itti_alloc_new_message(TASK_X2AP, 0, SCTP_NEW_ASSOCIATION_REQ); + sctp_new_association_req_t *sctp_new_association_req = &message->ittiMsg.sctp_new_association_req; sctp_new_association_req->port = enb_port_for_X2C; sctp_new_association_req->ppid = X2AP_SCTP_PPID; sctp_new_association_req->in_streams = in_streams; sctp_new_association_req->out_streams = out_streams; - sctp_new_association_req->multi_sd = multi_sd; memcpy(&sctp_new_association_req->remote_address, target_eNB_ip_address, sizeof(*target_eNB_ip_address)); @@ -399,8 +395,7 @@ void x2ap_eNB_handle_sctp_init_msg_multi_cnf( &instance->enb_x2_ip_address, instance->sctp_in_streams, instance->sctp_out_streams, - instance->enb_port_for_X2C, - instance->multi_sd); + instance->enb_port_for_X2C); } } @@ -645,7 +640,8 @@ void *x2ap_task(void *arg) { while (1) { itti_receive_msg(TASK_X2AP, &received_msg); - + LOG_D(X2AP, "Received message %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); switch (ITTI_MSG_ID(received_msg)) { case TERMINATE_MESSAGE: X2AP_WARN(" *** Exiting X2AP thread\n"); @@ -684,7 +680,6 @@ void *x2ap_task(void *arg) { case X2AP_ENDC_SGNB_ADDITION_REQ_ACK: x2ap_gNB_trigger_sgNB_add_req_ack(ITTI_MSG_DESTINATION_INSTANCE(received_msg), &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(received_msg)); - LOG_I(X2AP, "Received elements for X2AP_ENDC_SGNB_ADDITION_REQ_ACK \n"); break; case X2AP_ENDC_SGNB_RECONF_COMPLETE: diff --git a/openair3/SCTP/sctp_common.h b/openair3/SCTP/sctp_common.h index ecaeebd090..024feb8b09 100644 --- a/openair3/SCTP/sctp_common.h +++ b/openair3/SCTP/sctp_common.h @@ -37,7 +37,7 @@ #if defined(ENB_MODE) # include "common/utils/LOG/log.h" # define SCTP_ERROR(x, args...) LOG_E(SCTP, x, ##args) -# define SCTP_DEBUG(x, args...) LOG_I(SCTP, x, ##args) +# define SCTP_DEBUG(x, args...) LOG_D(SCTP, x, ##args) # define SCTP_WARN(x, args...) LOG_W(SCTP, x, ##args) #else # define SCTP_ERROR(x, args...) do { fprintf(stderr, "[SCTP][E]"x, ##args); } while(0) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index ab49125856..06e606e36b 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -318,7 +318,8 @@ sctp_handle_new_association_req_multi( assoc_id, used_address); } } else { - SCTP_DEBUG("sctp_connectx SUCCESS, used %d addresses assoc_id %d\n", + SCTP_DEBUG("sctp_connectx SUCCESS, socket %d used %d addresses assoc_id %d\n", + sd, used_address, assoc_id); } @@ -750,7 +751,7 @@ static int sctp_create_new_listener( } if (server_type) { - if ((sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) { + if ((sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) { SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno); free(addr); return -1; @@ -822,7 +823,7 @@ static int sctp_create_new_listener( sctp_cnx = NULL; return -1; } - + SCTP_DEBUG("Created listen socket: %d\n", sd); /* Insert new element at end of list */ STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries); sctp_nb_cnx++; @@ -1110,11 +1111,10 @@ void *sctp_eNB_process_itti_msg(void *notUsed) /* Check if there is a packet to handle */ if (received_msg != NULL) { + LOG_D(SCTP,"Received message %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); switch (ITTI_MSG_ID(received_msg)) { case SCTP_INIT_MSG: { - SCTP_DEBUG("Received SCTP_INIT_MSG\n"); - - /* We received a new connection request */ if (sctp_create_new_listener( ITTI_MSG_DESTINATION_INSTANCE(received_msg), ITTI_MSG_ORIGIN_ID(received_msg), @@ -1126,11 +1126,7 @@ void *sctp_eNB_process_itti_msg(void *notUsed) break; case SCTP_INIT_MSG_MULTI_REQ: { - int multi_sd; - - SCTP_DEBUG("Received SCTP_INIT_MSG_MULTI_REQ\n"); - - multi_sd = sctp_create_new_listener( + int multi_sd = sctp_create_new_listener( ITTI_MSG_DESTINATION_INSTANCE(received_msg), ITTI_MSG_ORIGIN_ID(received_msg), &received_msg->ittiMsg.sctp_init_multi,1); From 65f09fecb8e6daf48ecba36a80a7a61612ff734b Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 14:18:05 +0100 Subject: [PATCH 148/226] First code simplification in UL channel estimation --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index c3360f692e..f2871eef10 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -321,43 +321,27 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; ul_ch+=8; - for (pilot_cnt=3; pilot_cnt<(6*nb_rb_pusch-3); pilot_cnt += 2) { + for (pilot_cnt=3; pilot_cnt<(6*nb_rb_pusch-3); pilot_cnt++) { ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - #ifdef DEBUG_PUSCH - printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); - #endif - multadd_real_vector_complex_scalar(fm, - ch, - ul_ch, - 8); - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; - //printf("ul_ch addr %p\n",ul_ch); +#ifdef DEBUG_PUSCH + printf("pilot %4u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", + pilot_cnt, pil[0], pil[1], rxF[0], rxF[1], ch[0], ch[1]); + //printf("data %4u: rxF -> (%4d,%4d) (%2d)\n",pilot_cnt, rxF[2], rxF[3], dBc(rxF[2], rxF[3])); +#endif - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - - #ifdef DEBUG_PUSCH - printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+1,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); - #endif - multadd_real_vector_complex_scalar(fmm, - ch, - ul_ch, - 8); - - //for (int i= 0; i<16; i++) - //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); + if (pilot_cnt%2 == 0) { + multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); + ul_ch+=8; + } else { + multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); + } pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; - ul_ch+=8; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; } // Treat first 2 pilots specially (right edge) From 454dc0cfab3d378ee3e488b5b64f3e92232c4f55 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Thu, 31 Mar 2022 12:19:00 +0530 Subject: [PATCH 149/226] Fixed memory leaks identified by address san There is still a leak that needs to be fixed in rrc_UE.c Should properly free NR_BCCH_BCH_Message_t *bcch_message after asn decoder using ASN_STRUCT_FREE() --- openair2/RRC/NR_UE/rrc_UE.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 6a678d0e18..7dca9b2774 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -359,7 +359,8 @@ void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type, return; } nr_rrc_ue_process_rrcReconfiguration(module_id,RRCReconfiguration); - } + ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, RRCReconfiguration); + } break; case nr_RadioBearerConfigX_r15: @@ -392,6 +393,7 @@ void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type, else if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *) RadioBearerConfig); } + ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, RadioBearerConfig); } break; From 4ecb0401e036a48cca294d449681cee49aeb7782 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 14:34:43 +0100 Subject: [PATCH 150/226] Second code simplification in UL channel estimation --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 101 ++---------------- 1 file changed, 7 insertions(+), 94 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index f2871eef10..acf69fbba2 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -227,101 +227,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, //if ((gNB->frame_parms.N_RB_UL&1)==0) { if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && gNB->prb_interpolation == 0){ + LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); - // Treat first 2 pilots specially (left edge) - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_PUSCH - LOG_I(PHY, "In %s ch 0 %d\n", __FUNCTION__, ((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])); - LOG_I(PHY, "In %s pilot 0 : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n", - __FUNCTION__, - rxF[0], - rxF[1], - dBc(rxF[0],rxF[1]), - ch[0], - ch[1], - dBc(ch[0],ch[1]), - pil[0], - pil[1]); - LOG_I(PHY, "In %s data 0 : rxF - > (%d,%d) (%d)\n", __FUNCTION__, rxF[2], rxF[3], dBc(rxF[2],rxF[3])); -#endif - - multadd_real_vector_complex_scalar(fl, - ch, - ul_ch, - 8); - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; - //for (int i= 0; i<8; i++) - //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); - - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - -#ifdef DEBUG_PUSCH - LOG_I(PHY, "In %s pilot 1 : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n", - __FUNCTION__, - rxF[0], - rxF[1], - dBc(rxF[0],rxF[1]), - ch[0], - ch[1], - dBc(ch[0],ch[1]), - pil[0], - pil[1]); - LOG_I(PHY, "In %s data 1 : rxF - > (%d,%d) (%d)\n", - __FUNCTION__, - rxF[2], - rxF[3], - dBc(rxF[2],rxF[3])); -#endif - - multadd_real_vector_complex_scalar(fml, - ch, - ul_ch, - 8); - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; - //printf("ul_ch addr %p\n",ul_ch); - - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - -#ifdef DEBUG_PUSCH - LOG_I(PHY, "In %s pilot 2 : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n", - __FUNCTION__, - rxF[0], - rxF[1], - dBc(rxF[0],rxF[1]), - ch[0], - ch[1], - dBc(ch[0],ch[1]), - pil[0], - pil[1]); - LOG_I(PHY, "In %s data 2 : rxF - > (%d,%d) (%d)\n", - __FUNCTION__, - rxF[2], - rxF[3], - dBc(rxF[2],rxF[3])); -#endif - - multadd_real_vector_complex_scalar(fmm, - ch, - ul_ch, - 8); - - //for (int i= 0; i<16; i++) - //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); - - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; - ul_ch+=8; - - for (pilot_cnt=3; pilot_cnt<(6*nb_rb_pusch-3); pilot_cnt++) { + for (pilot_cnt = 0; pilot_cnt < (6*nb_rb_pusch-3); pilot_cnt++) { ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -332,7 +241,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, //printf("data %4u: rxF -> (%4d,%4d) (%2d)\n",pilot_cnt, rxF[2], rxF[3], dBc(rxF[2], rxF[3])); #endif - if (pilot_cnt%2 == 0) { + if (pilot_cnt == 0) { + multadd_real_vector_complex_scalar(fl, ch, ul_ch, 8); + } else if (pilot_cnt == 1) { + multadd_real_vector_complex_scalar(fml, ch, ul_ch, 8); + } else if (pilot_cnt%2 == 0) { multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); ul_ch+=8; } else { From 735b51a06b59228ef41c26ca8ea7e1d1ce133d2a Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 15:03:26 +0100 Subject: [PATCH 151/226] Third code simplification in UL channel estimation --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 81 ++++--------------- 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index acf69fbba2..2e3d9d8c56 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -230,7 +230,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); - for (pilot_cnt = 0; pilot_cnt < (6*nb_rb_pusch-3); pilot_cnt++) { + for (pilot_cnt = 0; pilot_cnt < 6*nb_rb_pusch; pilot_cnt++) { ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -245,6 +245,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, multadd_real_vector_complex_scalar(fl, ch, ul_ch, 8); } else if (pilot_cnt == 1) { multadd_real_vector_complex_scalar(fml, ch, ul_ch, 8); + } else if (pilot_cnt == (6*nb_rb_pusch-2)) { + multadd_real_vector_complex_scalar(fmr, ch, ul_ch, 8); + ul_ch+=8; + } else if (pilot_cnt == (6*nb_rb_pusch-1)) { + multadd_real_vector_complex_scalar(fr, ch, ul_ch, 8); } else if (pilot_cnt%2 == 0) { multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); ul_ch+=8; @@ -256,54 +261,6 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; } - - // Treat first 2 pilots specially (right edge) - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_PUSCH - printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); -#endif - multadd_real_vector_complex_scalar(fm, - ch, - ul_ch, - 8); - - //for (int i= 0; i<8; i++) - //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); - - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; - - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_PUSCH - printf("ch 0 %d\n",((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])); - printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+1,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); -#endif - multadd_real_vector_complex_scalar(fmr, - ch, - ul_ch, - 8); - - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; - ul_ch+=8; - - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_PUSCH - printf("pilot %u: rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+2,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]); - printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+2,rxF[2],rxF[3],dBc(rxF[2],rxF[3])); -#endif - multadd_real_vector_complex_scalar(fr, - ch, - ul_ch, - 8); - // check if PRB crosses DC and improve estimates around DC if ((bwp_start_subcarrier < gNB->frame_parms.ofdm_symbol_size) && (bwp_start_subcarrier+nb_rb_pusch*12 >= gNB->frame_parms.ofdm_symbol_size)) { @@ -323,10 +280,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // for proper allignment of SIMD vectors if((gNB->frame_parms.N_RB_UL&1)==0) { - multadd_real_vector_complex_scalar(fdcl, - ch, - ul_ch-4, - 8); + multadd_real_vector_complex_scalar(fdcl, ch, ul_ch-4, 8); pil += 4; re_offset = (re_offset+4) % gNB->frame_parms.ofdm_symbol_size; @@ -334,16 +288,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - multadd_real_vector_complex_scalar(fdcr, - ch, - ul_ch-4, - 8); - } - else { - multadd_real_vector_complex_scalar(fdclh, - ch, - ul_ch, - 8); + multadd_real_vector_complex_scalar(fdcr, ch, ul_ch-4, 8); + + } else { + + multadd_real_vector_complex_scalar(fdclh, ch, ul_ch, 8); pil += 4; re_offset = (re_offset+4) % gNB->frame_parms.ofdm_symbol_size; @@ -351,12 +300,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - multadd_real_vector_complex_scalar(fdcrh, - ch, - ul_ch, - 8); + multadd_real_vector_complex_scalar(fdcrh, ch, ul_ch, 8); } } + #ifdef DEBUG_PUSCH ul_ch = (int16_t *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; for(uint16_t idxP=0; idxP Date: Thu, 28 Apr 2022 16:24:21 +0100 Subject: [PATCH 152/226] Improve debug log --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 2e3d9d8c56..b55a9694d8 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -307,10 +307,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, #ifdef DEBUG_PUSCH ul_ch = (int16_t *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; for(uint16_t idxP=0; idxP Date: Thu, 28 Apr 2022 18:08:20 +0200 Subject: [PATCH 153/226] Update for the code review comment. Instead of NULL RAND value check, added the flag to indicate if the AUTH process started. The flag is used manage the timer handling for authentication process when stored RAND values is same as received RAND value in AUTH_REQ. --- openair3/NAS/UE/EMM/Authentication.c | 7 ++++--- openair3/NAS/UE/EMM/Authentication.h | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index 97c7082be0..36c90c4ab0 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -180,13 +180,14 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, OctetString res = {AUTH_RES_SIZE, authentication_data->res}; if ((memcmp(authentication_data->rand, rand->value, AUTH_CK_SIZE) != 0) || - (memcmp(nullRand,authentication_data->rand, AUTH_CK_SIZE) == 0)) { + (authentication_data->auth_process_started == FALSE)) { /* * There is no valid stored RAND in the ME or the stored RAND is * different from the new received value in the AUTHENTICATION - * REQUEST message OR the received RAND is all "0" or "NULL" - * process the new received AUTHENTICATIOn REQUEST message + * REQUEST message OR if this is first time UE starting the + * Authentication process */ + authentication_data->auth_process_started = TRUE; OctetString auts; auts.length = 0; auts.value = (uint8_t *)malloc(AUTH_AUTS_SIZE); diff --git a/openair3/NAS/UE/EMM/Authentication.h b/openair3/NAS/UE/EMM/Authentication.h index 50b2d990aa..466d3256f3 100644 --- a/openair3/NAS/UE/EMM/Authentication.h +++ b/openair3/NAS/UE/EMM/Authentication.h @@ -18,6 +18,8 @@ typedef struct { unsigned char mac_count:2; /* MAC failure counter (#20) */ unsigned char umts_count:2; /* UMTS challenge failure counter (#26) */ unsigned char sync_count:2; /* Sync failure counter (#21) */ + unsigned char auth_process_started:1; /* Authentication started */ + unsigned char reserve:1; /* For future use, byte aligned */ } authentication_data_t; #endif From 927e2195534396ee6f7837891efb1aa54e3033fd Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 21:04:41 +0100 Subject: [PATCH 154/226] UL channel estimation with a formulation closer to 3GPP, because this will be useful next --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 106 ++++++++++++------ openair1/PHY/NR_REFSIG/nr_dmrs_rx.c | 2 +- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index b55a9694d8..5a196a4030 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -76,6 +76,10 @@ void freq2time(uint16_t ofdm_symbol_size, } } +// Table 6.4.1.1.3-1/2 from TS 38.211 +const uint16_t delta1[8] = {0, 0, 1, 1, 0, 0, 1, 1}; +const uint16_t delta2[12] = {0, 0, 2, 2, 4, 4, 0, 0, 2, 2, 4, 4}; + int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, unsigned char Ns, unsigned short p, @@ -86,7 +90,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int pilot[3280] __attribute__((aligned(16))); unsigned char aarx; - unsigned short k; + unsigned short k0; unsigned int pilot_cnt,re_cnt; int16_t ch[2],ch_r[2],ch_l[2],*pil,*rxF,*ul_ch; int16_t *fl,*fm,*fr,*fml,*fmr,*fmm,*fdcl,*fdcr,*fdclh,*fdcrh; @@ -112,18 +116,18 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, symbol_offset = gNB->frame_parms.ofdm_symbol_size*symbol; - k = bwp_start_subcarrier; + k0 = bwp_start_subcarrier; int re_offset; uint16_t nb_rb_pusch = pusch_pdu->rb_size; - LOG_D(PHY, "In %s: ch_offset %d, soffset %d, symbol_offset %d OFDM size %d, Ns = %d, k = %d symbol %d\n", + LOG_D(PHY, "In %s: ch_offset %d, soffset %d, symbol_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n", __FUNCTION__, ch_offset, soffset, symbol_offset, gNB->frame_parms.ofdm_symbol_size, Ns, - k, + k0, symbol); switch (nushift) { @@ -206,60 +210,92 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } #endif + // Based on Table 6.4.1.1.3-1/2 from TS 38.211 + int delta = 0; + //int deltas[3] = {0}; + //int n_delta = 0; + if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { + delta = delta1[p]; + /*if (pusch_pdu->nrOfLayers <= 2) { + n_delta = 1; + } else { + n_delta = 2; + deltas[1] = 1; + }*/ + } else { + delta = delta2[p]; + /*if (pusch_pdu->nrOfLayers <= 2) { + n_delta = 1; + } else if (pusch_pdu->nrOfLayers <= 4) { + n_delta = 2; + deltas[1] = 2; + } else { + n_delta = 3; + deltas[1] = 2; + deltas[2] = 4; + }*/ + } + for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { - re_offset = k; /* Initializing the Resource element offset for each Rx antenna */ - pil = (int16_t *)&pilot[0]; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+k+nushift)]; + rxF = (int16_t *)&rxdataF[aarx][(soffset + symbol_offset + k0 + nushift)]; ul_ch = (int16_t *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; - re_offset = k; + re_offset = k0; memset(ul_ch,0,4*(gNB->frame_parms.ofdm_symbol_size)); #ifdef DEBUG_PUSCH LOG_I(PHY, "In %s symbol_offset %d, nushift %d\n", __FUNCTION__, symbol_offset, nushift); LOG_I(PHY, "In %s ch est pilot addr %p, N_RB_UL %d\n", __FUNCTION__, &pilot[0], gNB->frame_parms.N_RB_UL); - LOG_I(PHY, "In %s bwp_start_subcarrier %d, k %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k, gNB->frame_parms.first_carrier_offset, nb_rb_pusch); + LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch); LOG_I(PHY, "In %s rxF addr %p p %d\n", __FUNCTION__, rxF, p); LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift); #endif - //if ((gNB->frame_parms.N_RB_UL&1)==0) { if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && gNB->prb_interpolation == 0){ LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); - for (pilot_cnt = 0; pilot_cnt < 6*nb_rb_pusch; pilot_cnt++) { + // For configuration type 1: k = 4*n + 2*k' + delta, + // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); + pilot_cnt = 0; + for (int n = 0; n < 3*nb_rb_pusch; n++) { + for (int k_line = 0; k_line <= 1; k_line++) { + + pilot_cnt++; + + re_offset = (k0 + (n<<2) + (k_line<<1) + delta) % gNB->frame_parms.ofdm_symbol_size; + rxF = (int16_t *)&rxdataF[aarx][(soffset + symbol_offset + re_offset)]; + + ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); #ifdef DEBUG_PUSCH - printf("pilot %4u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", - pilot_cnt, pil[0], pil[1], rxF[0], rxF[1], ch[0], ch[1]); - //printf("data %4u: rxF -> (%4d,%4d) (%2d)\n",pilot_cnt, rxF[2], rxF[3], dBc(rxF[2], rxF[3])); + printf("pilot %4u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", + pilot_cnt, pil[0], pil[1], rxF[0], rxF[1], ch[0], ch[1]); + //printf("data %4u: rxF -> (%4d,%4d) (%2d)\n",pilot_cnt, rxF[2], rxF[3], dBc(rxF[2], rxF[3])); #endif - if (pilot_cnt == 0) { - multadd_real_vector_complex_scalar(fl, ch, ul_ch, 8); - } else if (pilot_cnt == 1) { - multadd_real_vector_complex_scalar(fml, ch, ul_ch, 8); - } else if (pilot_cnt == (6*nb_rb_pusch-2)) { - multadd_real_vector_complex_scalar(fmr, ch, ul_ch, 8); - ul_ch+=8; - } else if (pilot_cnt == (6*nb_rb_pusch-1)) { - multadd_real_vector_complex_scalar(fr, ch, ul_ch, 8); - } else if (pilot_cnt%2 == 0) { - multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); - ul_ch+=8; - } else { - multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); - } + if (pilot_cnt == 0) { + multadd_real_vector_complex_scalar(fl, ch, ul_ch, 8); + } else if (pilot_cnt == 1) { + multadd_real_vector_complex_scalar(fml, ch, ul_ch, 8); + } else if (pilot_cnt == (6*nb_rb_pusch-2)) { + multadd_real_vector_complex_scalar(fmr, ch, ul_ch, 8); + ul_ch+=8; + } else if (pilot_cnt == (6*nb_rb_pusch-1)) { + multadd_real_vector_complex_scalar(fr, ch, ul_ch, 8); + } else if (pilot_cnt%2 == 0) { + multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); + ul_ch+=8; + } else { + multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); + } - pil += 2; - re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; + pil += 2; + } } // check if PRB crosses DC and improve estimates around DC @@ -267,7 +303,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ul_ch = (int16_t *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; uint16_t idxDC = 2*(gNB->frame_parms.ofdm_symbol_size - bwp_start_subcarrier); uint16_t idxPil = idxDC/2; - re_offset = k; + re_offset = k0; pil = (int16_t *)&pilot[0]; pil += (idxPil-2); ul_ch += (idxDC-4); diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 920b78eac2..4a8aaab4cb 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -39,7 +39,7 @@ #include "nr_refsig.h" #include "PHY/defs_gNB.h" -/*Table 7.4.1.1.2-1/2 from 38.211 */ +// Table 6.4.1.1.3-1/2 from TS 38.211 int wf1[8][2] = {{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1}}; int wt1[8][2] = {{1,1},{1,1},{1,1},{1,1},{1,-1},{1,-1},{1,-1},{1,-1}}; int wf2[12][2] = {{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1}}; From 724e155a3a7d9e7f7467921cd285e1007cb61039 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 28 Apr 2022 23:57:19 +0100 Subject: [PATCH 155/226] Move UL delta computation for a function --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 23 ++++++++----------- openair1/PHY/NR_REFSIG/nr_dmrs_rx.c | 9 ++++++++ openair1/PHY/NR_REFSIG/nr_refsig.h | 2 ++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 5a196a4030..633d453494 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -76,10 +76,6 @@ void freq2time(uint16_t ofdm_symbol_size, } } -// Table 6.4.1.1.3-1/2 from TS 38.211 -const uint16_t delta1[8] = {0, 0, 1, 1, 0, 0, 1, 1}; -const uint16_t delta2[12] = {0, 0, 2, 2, 4, 4, 0, 0, 2, 2, 4, 4}; - int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, unsigned char Ns, unsigned short p, @@ -211,20 +207,17 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, #endif // Based on Table 6.4.1.1.3-1/2 from TS 38.211 - int delta = 0; - //int deltas[3] = {0}; - //int n_delta = 0; + /*int deltas[3] = {0}; + int n_delta = 0; if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { - delta = delta1[p]; - /*if (pusch_pdu->nrOfLayers <= 2) { + if (pusch_pdu->nrOfLayers <= 2) { n_delta = 1; } else { n_delta = 2; deltas[1] = 1; - }*/ + } } else { - delta = delta2[p]; - /*if (pusch_pdu->nrOfLayers <= 2) { + if (pusch_pdu->nrOfLayers <= 2) { n_delta = 1; } else if (pusch_pdu->nrOfLayers <= 4) { n_delta = 2; @@ -233,8 +226,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, n_delta = 3; deltas[1] = 2; deltas[2] = 4; - }*/ - } + } + }*/ for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { @@ -260,6 +253,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // For configuration type 1: k = 4*n + 2*k' + delta, // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 + int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p); + pilot_cnt = 0; for (int n = 0; n < 3*nb_rb_pusch; n++) { for (int k_line = 0; k_line <= 1; k_line++) { diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 4a8aaab4cb..4f089562f6 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -40,8 +40,10 @@ #include "PHY/defs_gNB.h" // Table 6.4.1.1.3-1/2 from TS 38.211 +int delta1[8] = {0, 0, 1, 1, 0, 0, 1, 1}; int wf1[8][2] = {{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1}}; int wt1[8][2] = {{1,1},{1,1},{1,1},{1,1},{1,-1},{1,-1},{1,-1},{1,-1}}; +int delta2[12] = {0, 0, 2, 2, 4, 4, 0, 0, 2, 2, 4, 4}; int wf2[12][2] = {{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1},{1,1},{1,-1}}; int wt2[12][2] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,-1},{1,-1},{1,-1},{1,-1},{1,-1},{1,-1}}; @@ -49,6 +51,13 @@ int wt2[12][2] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,-1},{1,-1},{1,-1},{1,-1 short nr_rx_mod_table[14] = {0,0,23170,-23170,-23170,23170,23170,-23170,23170,23170,-23170,-23170,-23170,23170}; short nr_rx_nmod_table[14] = {0,0,-23170,23170,23170,-23170,-23170,23170,-23170,-23170,23170,23170,23170,-23170}; +int nr_pusch_dmrs_delta(uint8_t dmrs_config_type, unsigned short p) { + if (dmrs_config_type == pusch_dmrs_type1) { + return delta1[p]; + } else { + return delta2[p]; + } +} int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned int Ns, diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index df3dad1e59..ad632431eb 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -42,6 +42,8 @@ void nr_init_csi_rs(PHY_VARS_gNB* gNB, uint32_t Nid); void nr_gold_pusch(PHY_VARS_gNB* gNB, int nscid, uint32_t nid); +int nr_pusch_dmrs_delta(uint8_t dmrs_config_type, unsigned short p); + int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned int Ns, unsigned int *nr_gold_pusch, From 719d7fb8be19a584454334a5d6ff2013dd3feb28 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Apr 2022 00:51:55 +0100 Subject: [PATCH 156/226] Improvements in UL channel estimation to consider multiple antennas for dmrs type 1 --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 633d453494..9bc93938ce 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -246,33 +246,41 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift); #endif - if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && gNB->prb_interpolation == 0){ + if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && gNB->prb_interpolation == 0) { LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); // For configuration type 1: k = 4*n + 2*k' + delta, // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 - int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p); - pilot_cnt = 0; + for (int n = 0; n < 3*nb_rb_pusch; n++) { + + // LS estimation + ch[0] = 0; + ch[1] = 0; + for (int p2 = 0; p2nrOfLayers; p2+=2) { + int delta2 = nr_pusch_dmrs_delta(pusch_dmrs_type1, p2); + for (int k_line = 0; k_line <= 1; k_line++) { + re_offset = (k0 + (n << 2) + (k_line << 1) + delta2) % gNB->frame_parms.ofdm_symbol_size; + rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; + ch[0] += (int16_t) (((int32_t) pil[0] * rxF[0] - (int32_t) pil[1] * rxF[1]) >> 15); + ch[1] += (int16_t) (((int32_t) pil[0] * rxF[1] + (int32_t) pil[1] * rxF[0]) >> 15); + pil += 2; + } + } + + // Channel interpolation for (int k_line = 0; k_line <= 1; k_line++) { - pilot_cnt++; - - re_offset = (k0 + (n<<2) + (k_line<<1) + delta) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(soffset + symbol_offset + re_offset)]; - - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); - ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); - #ifdef DEBUG_PUSCH + re_offset = (k0 + (n << 2) + (k_line << 1)) % gNB->frame_parms.ofdm_symbol_size; + rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; printf("pilot %4u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", pilot_cnt, pil[0], pil[1], rxF[0], rxF[1], ch[0], ch[1]); //printf("data %4u: rxF -> (%4d,%4d) (%2d)\n",pilot_cnt, rxF[2], rxF[3], dBc(rxF[2], rxF[3])); #endif - if (pilot_cnt == 0) { multadd_real_vector_complex_scalar(fl, ch, ul_ch, 8); } else if (pilot_cnt == 1) { @@ -288,8 +296,6 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } else { multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); } - - pil += 2; } } From c128a5d9e298d17e13dd24e63b9fc5e433b1e9c3 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Apr 2022 01:11:27 +0100 Subject: [PATCH 157/226] Remove SUPPORT_PMI_MATRIC flag --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 16c58210e4..c22fb011f1 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -359,25 +359,15 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t)); } - #ifdef SUPPORT_PMI_MATRIC - for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) - #else - aatx = aarx; - #endif - { + for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) { ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; - memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); } } else { - #ifdef SUPPORT_PMI_MATRIC - for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) - #else - aatx = aarx; - #endif - { + + for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) { ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; @@ -2098,11 +2088,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->ul_ch_mag0, gNB->pusch_vars[ulsch_id]->ul_ch_magb0, gNB->pusch_vars[ulsch_id]->rxdataF_comp, - #ifdef SUPPORT_PMI_MATRIC (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, - #else - NULL, - #endif frame_parms, symbol, nb_re_pusch, @@ -2118,11 +2104,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->rxdataF_comp, gNB->pusch_vars[ulsch_id]->ul_ch_mag0, gNB->pusch_vars[ulsch_id]->ul_ch_magb0, - #ifdef SUPPORT_PMI_MATRIC (rel15_ul->nrOfLayers>1) ? gNB->pusch_vars[ulsch_id]->rho : NULL, - #else - NULL, - #endif rel15_ul->nrOfLayers, symbol, rel15_ul->rb_size, From e23679431063b42a091f515cec3da3f381b5277b Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Apr 2022 01:22:33 +0100 Subject: [PATCH 158/226] Put in ulsim a channel matrix H_awgn_mimo different from identity (it is a matrix equal to matrix used in dlsim) --- openair1/SIMULATION/NR_PHY/ulsim.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 6521324bec..b64b4c22c5 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1260,23 +1260,19 @@ int main(int argc, char **argv) for (i=0; inb_antennas_rx; ap++) { if (channel_model == AWGN) { - double H_awgn[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 - {0.0, 1.0, 0.0, 0.0}, //rx 1 - {0.0, 0.0, 1.0, 0.0}, //rx 2 - {0.0, 0.0, 0.0, 1.0}};//rx 3 - #if 0 - double H_awgn_mimo[4][4] ={{1.0, 0.5, 0.25, 0.125},//rx 0 - {0.5, 1.0, 0.5, 0.25}, //rx 1 - {0.25, 0.5, 1.0, 0.5}, //rx 2 - {0.125, 0.25, 0.5, 1.0}};//rx 3 - #endif + + double H_awgn_mimo[4][4] ={{1.0, 0.2, 0.1, 0.05}, //rx 0 + {0.2, 1.0, 0.2, 0.1}, //rx 1 + {0.1, 0.2, 1.0, 0.2}, //rx 2 + {0.05, 0.1, 0.2, 1.0}}; //rx 3 + // sum up signals from different Tx antennas r_re[ap][i] = 0; r_im[ap][i] = 0; for (int aa=0; aa Date: Fri, 29 Apr 2022 11:00:40 +0100 Subject: [PATCH 159/226] Fix high MCS test fail for UL (it do not fix the degradation yet) --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 9bc93938ce..e180be6604 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -206,28 +206,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } #endif - // Based on Table 6.4.1.1.3-1/2 from TS 38.211 - /*int deltas[3] = {0}; - int n_delta = 0; - if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { - if (pusch_pdu->nrOfLayers <= 2) { - n_delta = 1; - } else { - n_delta = 2; - deltas[1] = 1; - } - } else { - if (pusch_pdu->nrOfLayers <= 2) { - n_delta = 1; - } else if (pusch_pdu->nrOfLayers <= 4) { - n_delta = 2; - deltas[1] = 2; - } else { - n_delta = 3; - deltas[1] = 2; - deltas[2] = 4; - } - }*/ + uint8_t b_shift = pusch_pdu->nrOfLayers < 4 ? 1 : log2_approx(pusch_pdu->nrOfLayers>>1); for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { @@ -265,8 +244,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, for (int k_line = 0; k_line <= 1; k_line++) { re_offset = (k0 + (n << 2) + (k_line << 1) + delta2) % gNB->frame_parms.ofdm_symbol_size; rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; - ch[0] += (int16_t) (((int32_t) pil[0] * rxF[0] - (int32_t) pil[1] * rxF[1]) >> 15); - ch[1] += (int16_t) (((int32_t) pil[0] * rxF[1] + (int32_t) pil[1] * rxF[0]) >> 15); + ch[0] += (int16_t) (((int32_t) pil[0] * rxF[0] - (int32_t) pil[1] * rxF[1]) >> (15+b_shift)); + ch[1] += (int16_t) (((int32_t) pil[0] * rxF[1] + (int32_t) pil[1] * rxF[0]) >> (15+b_shift)); pil += 2; } } From 523f8f2139797682971a94a6a1df44bde0e6b4f0 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Apr 2022 18:19:49 +0100 Subject: [PATCH 160/226] Put pilot_cnt++ in the right place --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index e180be6604..720a1e9b50 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -252,7 +252,6 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // Channel interpolation for (int k_line = 0; k_line <= 1; k_line++) { - pilot_cnt++; #ifdef DEBUG_PUSCH re_offset = (k0 + (n << 2) + (k_line << 1)) % gNB->frame_parms.ofdm_symbol_size; rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; @@ -275,6 +274,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } else { multadd_real_vector_complex_scalar(fm, ch, ul_ch, 8); } + pilot_cnt++; } } From 1694e1b061867837e950c19ae70c54944cc8326d Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Apr 2022 19:08:41 +0100 Subject: [PATCH 161/226] Fix b_shift --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 720a1e9b50..038f1473f9 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -206,7 +206,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } #endif - uint8_t b_shift = pusch_pdu->nrOfLayers < 4 ? 1 : log2_approx(pusch_pdu->nrOfLayers>>1); + uint8_t b_shift = pusch_pdu->nrOfLayers == 1; for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { From 0e2a00655e79b48743b361e7124a2e6ea738d84f Mon Sep 17 00:00:00 2001 From: rmagueta Date: Sat, 30 Apr 2022 17:07:14 +0100 Subject: [PATCH 162/226] Fix build after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 205fb90017..b3aab64bd8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1648,8 +1648,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->R = 0; ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->F = 1; ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->LCID = DL_SCH_LCID_CCCH; - ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->L1 = (mac_sdu_length >> 8) & 0xff; - ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->L2 = mac_sdu_length & 0xff; + ((NR_MAC_SUBHEADER_LONG *) &buf[mac_pdu_length])->L = htons(mac_sdu_length); ra->mac_pdu_length = mac_pdu_length + mac_sdu_length + sizeof(NR_MAC_SUBHEADER_LONG); } LOG_I(NR_MAC,"Encoded RRCSetup Piggyback (%d + %d bytes), mac_pdu_length %d\n", mac_sdu_length, mac_subheader_len, ra->mac_pdu_length); From 4f2854f92cd4c834592b21f9248ad5ae37d9753b Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 2 May 2022 01:55:03 +0100 Subject: [PATCH 163/226] Fix UL channel estimation for 4 layers --- cmake_targets/autotests/test_case_list.xml | 2 +- .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index f372e7230a..14daa644df 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1331,7 +1331,7 @@ -n100 -s5 -Z -U 2 0 2 -n100 -m19 -s10 -S15 -z2 -n100 -m9 -r106 -s10 -W2 -y2 -z2 - -n100 -m9 -r106 -s13 -W4 -y4 -z4 + -n100 -m9 -r106 -s20 -W4 -y4 -z4 nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 PUSCH test OK diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 038f1473f9..20575b45d1 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -233,21 +233,19 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 pilot_cnt = 0; + int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p); for (int n = 0; n < 3*nb_rb_pusch; n++) { // LS estimation ch[0] = 0; ch[1] = 0; - for (int p2 = 0; p2nrOfLayers; p2+=2) { - int delta2 = nr_pusch_dmrs_delta(pusch_dmrs_type1, p2); - for (int k_line = 0; k_line <= 1; k_line++) { - re_offset = (k0 + (n << 2) + (k_line << 1) + delta2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; - ch[0] += (int16_t) (((int32_t) pil[0] * rxF[0] - (int32_t) pil[1] * rxF[1]) >> (15+b_shift)); - ch[1] += (int16_t) (((int32_t) pil[0] * rxF[1] + (int32_t) pil[1] * rxF[0]) >> (15+b_shift)); - pil += 2; - } + for (int k_line = 0; k_line <= 1; k_line++) { + re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % gNB->frame_parms.ofdm_symbol_size; + rxF = (int16_t *) &rxdataF[aarx][(soffset + symbol_offset + re_offset)]; + ch[0] += (int16_t) (((int32_t) pil[0] * rxF[0] - (int32_t) pil[1] * rxF[1]) >> (15+b_shift)); + ch[1] += (int16_t) (((int32_t) pil[0] * rxF[1] + (int32_t) pil[1] * rxF[0]) >> (15+b_shift)); + pil += 2; } // Channel interpolation From 6b6528cc944be640b19ef0c83fa0522e9ff48f10 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 2 May 2022 10:41:42 +0200 Subject: [PATCH 164/226] revert H_awgn_mimo in simulator --- targets/ARCH/rfsimulator/simulator.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 38902984b6..127b2975d5 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -705,17 +705,10 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } else { // no channel modeling - #if 0 double H_awgn_mimo[4][4] ={{1.0, 0.2, 0.1, 0.05}, //rx 0 {0.2, 1.0, 0.2, 0.1}, //rx 1 {0.1, 0.2, 1.0, 0.2}, //rx 2 {0.05, 0.1, 0.2, 1.0}};//rx 3 - #else - double H_awgn_mimo[4][4] ={{1.0, 0.0, 0.0, 0.0},//rx 0 - {0.0, 1.0, 0.0, 0.0},//rx 1 - {0.0, 0.0, 1.0, 0.0},//rx 2 - {0.0, 0.0, 0.0, 1.0}};//rx 3 - #endif sample_t *out=(sample_t *)samplesVoid[a]; int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas From ca0666868239ed0b5d2abe6f8c4abb728230ef99 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 21 Mar 2022 14:35:41 +0000 Subject: [PATCH 165/226] Handle RRC processing time at gNB --- openair2/GNB_APP/gnb_config.c | 3 +- openair2/LAYER2/NR_MAC_gNB/config.c | 23 ++++++++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 3 ++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 7 +++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 23 ++++++---- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 22 ++++++++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 4 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 3 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 9 ++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 3 +- openair2/RRC/NR/nr_rrc_defs.h | 6 ++- openair2/RRC/NR/rrc_gNB.c | 43 +++++++++++++++++-- openair2/RRC/NR/rrc_gNB_nsa.c | 5 +-- 14 files changed, 130 insertions(+), 26 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 2c486ec832..0648249122 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2066,8 +2066,7 @@ void configure_gnb_du_mac(int inst) { NULL, 0, 0, // rnti - (NR_CellGroupConfig_t *)NULL - ); + NULL); } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index a2cbd4807f..ca709666eb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -449,6 +449,25 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts } +int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, rnti_t rnti, NR_SubcarrierSpacing_t subcarrierSpacing, uint32_t rrc_reconfiguration_delay) { + if (rrc_reconfiguration_delay > 0) { + const int UE_id = find_nr_UE_id(Mod_idP,rnti); + if (UE_id >= 0) { + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer == 0) { + const uint16_t sf_ahead = (uint16_t) ceil(6.0/(float)(0x01<rrc_processing_timer = (rrc_reconfiguration_delay<rnti); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; + + const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, + RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, + sib1); + // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs + sched_ctrl->rrc_processing_timer = (NR_RRC_SETUP_DELAY_MS << genericParameters->subcarrierSpacing); // RRCSetup 10 ms } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 53485886c0..ef6dfef45b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -488,17 +488,22 @@ void nr_store_dlsch_buffer(module_id_t module_id, const int lcid = sched_ctrl->dl_lc_ids[i]; const uint16_t rnti = UE_info->rnti[UE_id]; LOG_D(NR_MAC, "In %s: UE %d/%x: LCID %d\n", __FUNCTION__, UE_id, rnti, lcid); + + if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) { + continue; + } + start_meas(&RC.nrmac[module_id]->rlc_status_ind); sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, - rnti, - module_id, - frame, - slot, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - 0, - 0); + rnti, + module_id, + frame, + slot, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + 0, + 0); stop_meas(&RC.nrmac[module_id]->rlc_status_ind); if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 6f17556c91..b58e3280c3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2604,6 +2604,11 @@ void nr_csirs_scheduling(int Mod_idP, for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + + if (sched_ctrl->rrc_processing_timer > 0) { + continue; + } + NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || @@ -2791,6 +2796,23 @@ void nr_csirs_scheduling(int Mod_idP, } } +void nr_mac_update_timers(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + const NR_list_t *UE_list = &UE_info->list; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer--; + if (sched_ctrl->rrc_processing_timer == 0) { + LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); + sched_ctrl->update_pdsch_ps = true; + sched_ctrl->update_pusch_ps = true; + } + } + } +} /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg, nfapi_nr_coreset_t *coreset, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index bf2af3b388..8680cc25d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -125,7 +125,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.slot = -1; sched_ctrl->sched_srs.srs_scheduled = false; - if(!UE_info->Msg4_ACKed[UE_id]) { + if(!UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 43822d0cd0..ae9c2d97a3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -702,7 +702,9 @@ void nr_csi_meas_reporting(int Mod_idP, for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { const NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; + if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { + continue; + } if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; const NR_CSI_MeasConfig_t *csi_measconfig = CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 72061bb9ba..bbe135413b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1201,8 +1201,9 @@ void pf_ul(module_id_t module_id, const bool do_sched = nr_UE_is_to_be_scheduled(module_id, 0, UE_id, sched_pusch->frame, sched_pusch->slot); LOG_D(NR_MAC,"pf_ul: do_sched UE %d => %s\n",UE_id,do_sched ? "yes" : "no"); - if (B == 0 && !do_sched) + if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) { continue; + } /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled * based on data to transmit) */ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 399033abd0..54abee888b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -46,6 +46,11 @@ void config_common(int Mod_idP, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc); +int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, + rnti_t rnti, + NR_SubcarrierSpacing_t subcarrierSpacing, + uint32_t rrc_reconfiguration_delay); + int rrc_mac_config_req_gNB(module_id_t Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, @@ -64,6 +69,10 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, frame_t frameP, sub_frame_t subframeP); +void nr_mac_update_timers(module_id_t module_id, + frame_t frame, + sub_frame_t slot); + void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_rxP, sub_frame_t slot_rxP); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index e32e63a778..31cdd96af0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -646,12 +646,13 @@ typedef struct { /// UL HARQ processes that await retransmission NR_list_t retrans_ul_harq; NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information - /// number of active DL LCs uint8_t dl_lc_num; /// order in which DLSCH scheduler should allocate LCs uint8_t dl_lc_ids[NR_MAX_NUM_LCID]; + /// Timer for RRC processing procedures + uint32_t rrc_processing_timer; } NR_UE_sched_ctrl_t; typedef struct { diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index b26f8243a0..5cc3157bce 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -96,6 +96,10 @@ typedef struct nr_uid_linear_allocator_s { #define PROTOCOL_NR_RRC_CTXT_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_NR_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) +// 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs +#define NR_RRC_SETUP_DELAY_MS 10 +#define NR_RRC_RECONFIGURATION_DELAY_MS 10 +#define NR_RRC_BWP_SWITCHING_DELAY_MS 6 #define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! #define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 @@ -372,7 +376,7 @@ typedef struct gNB_RRC_UE_s { rb_id_t gnb_gtp_ebi[S1AP_MAX_E_RAB]; rb_id_t gnb_gtp_psi[S1AP_MAX_E_RAB]; //GTPV1 F1-U TUNNELS - uint32_t incoming_teid[S1AP_MAX_E_RAB]; + uint32_t incoming_teid[S1AP_MAX_E_RAB]; uint32_t ul_failure_timer; uint32_t ue_release_timer; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1715677c6d..4be59273c1 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -729,6 +729,13 @@ rrc_gNB_generate_defaultRRCReconfiguration( LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } + /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -995,6 +1002,13 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } + /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -1168,6 +1182,13 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } + /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { if (ue_context_pP->ue_context.modify_pdusession[i].param.nas_pdu.buffer != NULL) { @@ -1269,8 +1290,15 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( NULL); ue_context_pP->ue_context.pdu_session_release_command_flag = 1; - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, - "[MSG] RRC Reconfiguration\n"); + + LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ if (nas_length > 0) { @@ -1819,8 +1847,15 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( NULL, NULL, NULL); - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, - "[MSG] RRC Reconfiguration\n"); + + LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); + + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index bb66d1513b..fb8de46953 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -241,9 +241,8 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ cipher_algo, NR_SecurityConfig__keyToUse_secondary); } - NR_ServingCellConfig_t *scc = ue_context_p->ue_context.spCellConfig - ? ue_context_p->ue_context.spCellConfig->spCellConfigDedicated - : NULL; + NR_ServingCellConfig_t *scc = ue_context_p->ue_context.spCellConfig ? + ue_context_p->ue_context.spCellConfig->spCellConfigDedicated : NULL; fill_default_reconfig(carrier->servingcellconfigcommon, scc, reconfig_ies, From d8a127810c0a0a34f938b45414b5b7d7a08f006c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:35:36 +0100 Subject: [PATCH 166/226] Fix mcs table update during RRCReconfiguration --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 -- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 +--- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 23 +++++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index ca709666eb..b12454735d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -676,8 +676,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Modified UE_id %d/%x with CellGroup\n",UE_id,rnti); process_CellGroup(CellGroup,&UE_info->UE_sched_ctrl[UE_id]); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - sched_ctrl->update_pdsch_ps = true; - sched_ctrl->update_pusch_ps = true; const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; if (get_softmodem_params()->sa) { // add all available DL HARQ processes for this UE in SA diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index ef6dfef45b..7250bf4fcc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -593,7 +593,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ - if (ps->time_domain_allocation != tda || sched_ctrl->update_pdsch_ps) { + if (ps->time_domain_allocation != tda) { nr_set_pdsch_semi_static(sib1, scc, cg, @@ -603,7 +603,6 @@ bool allocate_dl_retransmission(module_id_t module_id, ps->nrOfLayers, sched_ctrl, ps); - sched_ctrl->update_pdsch_ps = false; } } else { /* the retransmission will use a different time domain allocation, check @@ -928,7 +927,6 @@ void pf_dl(module_id_t module_id, layers[UE_id], sched_ctrl, ps); - sched_ctrl->update_pdsch_ps = false; } const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index b58e3280c3..d7478474b1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -579,16 +579,21 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, bwpd = (NR_BWP_DownlinkDedicated_t*)bwpd0; } - if (bwpd && - bwpd->pdsch_Config && - bwpd->pdsch_Config->choice.setup && - bwpd->pdsch_Config->choice.setup->mcs_Table) { - if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) - ps->mcsTableIdx = 1; - else - ps->mcsTableIdx = 2; + if (sched_ctrl->update_pdsch_ps == true) { + if (bwpd && + bwpd->pdsch_Config && + bwpd->pdsch_Config->choice.setup && + bwpd->pdsch_Config->choice.setup->mcs_Table) { + if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) { + ps->mcsTableIdx = 1; + } else { + ps->mcsTableIdx = 2; + } + } else { + ps->mcsTableIdx = 0; + } + sched_ctrl->update_pdsch_ps = false; } - else ps->mcsTableIdx = 0; LOG_D(NR_MAC,"MCS Table Index: %d\n",ps->mcsTableIdx); NR_PDSCH_Config_t *pdsch_Config; From 8569a47bc62bda9a9b21815f6ea5a7750813fba3 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:37:19 +0100 Subject: [PATCH 167/226] Remove sib1_tda from configuration files to use default value --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 1 - targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - .../CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - 7 files changed, 7 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..92d1ce432c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -48,7 +48,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 256d724f3f..f95bdf91ae 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -38,7 +38,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 726e43d7ad..74f6c34f57 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - sib1_tda = 0; servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 7e2db64aaa..d124c5692f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..ff64fe718a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -36,7 +36,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 950e9c1d38..1bc6de3bfe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -35,7 +35,6 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; - sib1_tda = 0; do_SRS = 1; ul_prbblacklist = "51,52,53,54" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1dc903b811..a0cee6f9ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { From 4b7b621f00bc9c31e7fe35914df06f542d848659 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:43:03 +0100 Subject: [PATCH 168/226] Minor improvements and cleanup in 5G NR SA configuration files --- .../CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 13 ++++--------- .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 7 +------ .../CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 13 ++++--------- .../CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf | 13 ++++--------- 4 files changed, 13 insertions(+), 33 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index d124c5692f..e645094e8b 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -19,10 +19,6 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); @@ -33,7 +29,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - min_rxtxtime = 6; + min_rxtxtime = 2; do_SRS = 1; pdcch_ConfigSIB1 = ( @@ -218,7 +214,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 150; + pucch0_dtx_threshold = 100; ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -228,12 +224,11 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 0 - att_rx = 0; + att_tx = 6; + att_rx = 6; bands = [41]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; - sf_extension = 0; eNB_instances = [0]; #beamforming 1x4 matrix: bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 1bc6de3bfe..2881a77d48 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -19,10 +19,6 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); @@ -40,7 +36,7 @@ gNBs = pdcch_ConfigSIB1 = ( { - controlResourceSetZero = 11; + controlResourceSetZero = 12; searchSpaceZero = 0; } ); @@ -234,7 +230,6 @@ RUs = ( bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 75; - sf_extension = 0; eNB_instances = [0]; ##beamforming 1x2 matrix: 1 layer x 2 antennas bf_weights = [0x00007fff, 0x0000]; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index a0cee6f9ca..e3024737ee 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -19,10 +19,6 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); @@ -33,7 +29,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - min_rxtxtime = 6; + min_rxtxtime = 2; pdcch_ConfigSIB1 = ( { @@ -217,7 +213,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 150; + pucch0_dtx_threshold = 100; ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -227,12 +223,11 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 0 - att_rx = 0; + att_tx = 6; + att_rx = 6; bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; - sf_extension = 0; eNB_instances = [0]; #beamforming 1x4 matrix: bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf index 74f8f2cb3b..b8d71015c1 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf @@ -19,10 +19,6 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); @@ -33,12 +29,12 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 2; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 2; ul_prbblacklist = "79,80,81,82" pdcch_ConfigSIB1 = ( { - controlResourceSetZero = 11; + controlResourceSetZero = 12; searchSpaceZero = 10; } ); @@ -236,7 +232,7 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 200; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; ulsch_max_frame_inactivity = 0; } @@ -247,7 +243,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 120; + pucch0_dtx_threshold = 100; } ); @@ -261,7 +257,6 @@ RUs = ( bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 75; - sf_extension = 0; eNB_instances = [0]; ##beamforming 1x2 matrix: 1 layer x 2 antennas bf_weights = [0x00007fff, 0x0000]; From 79d9c2e8dc266ac61af188182f43f3a5af46cb38 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:50:08 +0100 Subject: [PATCH 169/226] Address review comments --- openair2/RRC/NR/rrc_gNB.c | 78 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4be59273c1..74e7997fba 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -729,13 +729,6 @@ rrc_gNB_generate_defaultRRCReconfiguration( LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { - nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, - ue_context_pP->ue_context.rnti, - *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); - } - /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -804,6 +797,13 @@ rrc_gNB_generate_defaultRRCReconfiguration( default : LOG_W(NR_RRC, "Unknown node type %d\n", RC.nrrrc[ctxt_pP->module_id]->node_type); } + + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } } //----------------------------------------------------------------------------- @@ -1002,13 +1002,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { - nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, - ue_context_pP->ue_context.rnti, - *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); - } - /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -1045,6 +1038,13 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( buffer, PDCP_TRANSMISSION_MODE_CONTROL); #endif + + if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } } //----------------------------------------------------------------------------- @@ -1182,13 +1182,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, - ue_context_pP->ue_context.rnti, - *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); - } - /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { if (ue_context_pP->ue_context.modify_pdusession[i].param.nas_pdu.buffer != NULL) { @@ -1225,6 +1218,13 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( buffer, PDCP_TRANSMISSION_MODE_CONTROL); #endif + + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } } //----------------------------------------------------------------------------- @@ -1290,15 +1290,8 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( NULL); ue_context_pP->ue_context.pdu_session_release_command_flag = 1; - - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, - ue_context_pP->ue_context.rnti, - *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); - } + LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, + "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ if (nas_length > 0) { @@ -1332,6 +1325,13 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( buffer, PDCP_TRANSMISSION_MODE_CONTROL); #endif + + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } } //----------------------------------------------------------------------------- @@ -1847,15 +1847,8 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( NULL, NULL, NULL); - - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, - ue_context_pP->ue_context.rnti, - *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); - } + LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, + "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { @@ -1897,6 +1890,13 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( PDCP_TRANSMISSION_MODE_CONTROL); #endif } + + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + NR_RRC_RECONFIGURATION_DELAY_MS); + } } //----------------------------------------------------------------------------- From 305347af9ae820c865968aa7683c3fcc5dc65591 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 14:13:01 +0100 Subject: [PATCH 170/226] Fix indentation and improve function nr_mac_enable_ue_rrc_processing_timer --- openair2/LAYER2/NR_MAC_gNB/config.c | 31 ++++++++--------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 33 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index b12454735d..9f7493e581 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -450,22 +450,23 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts } int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, rnti_t rnti, NR_SubcarrierSpacing_t subcarrierSpacing, uint32_t rrc_reconfiguration_delay) { - if (rrc_reconfiguration_delay > 0) { - const int UE_id = find_nr_UE_id(Mod_idP,rnti); - if (UE_id >= 0) { - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->rrc_processing_timer == 0) { - const uint16_t sf_ahead = (uint16_t) ceil(6.0/(float)(0x01<rrc_processing_timer = (rrc_reconfiguration_delay<UE_info; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const uint16_t sf_ahead = 6/(0x01<0); + const uint16_t sl_ahead = sf_ahead * (0x01<rrc_processing_timer = (rrc_reconfiguration_delay<> 3; + R, + 1, /* rbSize */ + 10, /* hypothetical number of slots */ + 0, /* N_PRB_DMRS * N_DMRS_SLOT */ + 0 /* N_PRB_oh, 0 for initialBWP */, + 0 /* tb_scaling */, + 1 /* nrOfLayers */) >> 3; } } @@ -1274,15 +1273,15 @@ void nr_schedule_ue_spec(module_id_t module_id, if (phaseTrackingRS) { bool valid_ptrs_setup = set_dl_ptrs_values(phaseTrackingRS->choice.setup, - pdsch_pdu->rbSize, - pdsch_pdu->mcsIndex[0], - pdsch_pdu->mcsTable[0], - &pdsch_pdu->PTRSFreqDensity, - &pdsch_pdu->PTRSTimeDensity, - &pdsch_pdu->PTRSPortIndex, - &pdsch_pdu->nEpreRatioOfPDSCHToPTRS, - &pdsch_pdu->PTRSReOffset, - pdsch_pdu->NrOfSymbols); + pdsch_pdu->rbSize, + pdsch_pdu->mcsIndex[0], + pdsch_pdu->mcsTable[0], + &pdsch_pdu->PTRSFreqDensity, + &pdsch_pdu->PTRSTimeDensity, + &pdsch_pdu->PTRSPortIndex, + &pdsch_pdu->nEpreRatioOfPDSCHToPTRS, + &pdsch_pdu->PTRSReOffset, + pdsch_pdu->NrOfSymbols); if (valid_ptrs_setup) pdsch_pdu->pduBitmap |= 0x1; // Bit 0: pdschPtrs - Indicates PTRS included (FR2) From be3498ddd282c7b6ba6cc05d594040415f11874a Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 14:26:17 +0100 Subject: [PATCH 171/226] Update documentation to be able to run OAI gNB with OAI UE and COTS UE with the same configuration file --- doc/RUNMODEM.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 919bbc2dc0..119027f169 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -165,7 +165,7 @@ From the `cmake_targets/ran_build/build` folder: gNB on machine 1: -`sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --sa` +`sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --sa` UE on machine 2: @@ -173,7 +173,7 @@ UE on machine 2: With the RF simulator (on the same machine): -`sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa` +`sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim --sa` `sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 -s 516 --rfsim --sa` From 5de85671d82fac4aefc666ed9c0c8232f112e228 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 2 May 2022 16:58:08 +0100 Subject: [PATCH 172/226] Fix heap buffer overflow --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index c22fb011f1..b11423b083 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -807,21 +807,17 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, int avg_rho_re[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; int avg_rho_im[frame_parms->nb_antennas_rx][nrOfLayers*nrOfLayers]; - for (aarx=0; aarxnb_antennas_rx; aarx++) - { - for (aatx=0; aatx < nrOfLayers; aatx++) - { - ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - - for (int atx=0; atx< nrOfLayers; atx++) - { + for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) { + for (aatx=0; aatx < nrOfLayers; aatx++) { + for (int atx=0; atx< nrOfLayers; atx++) { + avg_rho_re[aarx][aatx*nrOfLayers+atx] = 0; avg_rho_im[aarx][aatx*nrOfLayers+atx] = 0; rho128 = (__m128i *)&rho[aarx][aatx*nrOfLayers+atx][symbol*(off+(nb_rb*12))]; + ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ul_ch128_2 = (__m128i *)&ul_ch_estimates_ext[atx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - for (rb=0; rb Date: Mon, 2 May 2022 19:08:10 +0200 Subject: [PATCH 173/226] fix for ssb offset scaling issue --- openair1/PHY/INIT/nr_parms.c | 6 ++++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 6 ++++-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 7 ++++++- openair2/LAYER2/NR_MAC_gNB/config.c | 13 ++++++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 11 +++++++++-- 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 757a8d965f..458c8b3403 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -366,8 +366,10 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, uint8_t sco = 0; if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset<24)) || - ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) ) - sco = config->ssb_table.ssb_subcarrier_offset; + ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) ) { + if (fp->freq_range == nr_FR1) + sco = config->ssb_table.ssb_subcarrier_offset>>config->ssb_config.scs_common; + } fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco); set_Lmax(fp); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 22db636966..dca97bddf0 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -54,8 +54,10 @@ void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME uint8_t sco = 0; if (((fp->freq_range == nr_FR1) && (cfg->ssb_table.ssb_subcarrier_offset.value<24)) || - ((fp->freq_range == nr_FR2) && (cfg->ssb_table.ssb_subcarrier_offset.value<12)) ) - sco = cfg->ssb_table.ssb_subcarrier_offset.value; + ((fp->freq_range == nr_FR2) && (cfg->ssb_table.ssb_subcarrier_offset.value<12)) ) { + if (fp->freq_range == nr_FR1) + sco = cfg->ssb_table.ssb_subcarrier_offset.value>>cfg->ssb_config.scs_common.value; + } fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + sco); LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,sco); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 79ebaea70a..8e9442d00c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -354,13 +354,18 @@ int8_t nr_ue_decode_mib(module_id_t module_id, scs_ssb = get_softmodem_params()->numerology; band = mac->nr_band; ssb_start_symbol = get_ssb_start_symbol(band,scs_ssb,ssb_index); + int ssb_sc_offset_norm; + if (ssb_subcarrier_offset<24 && mac->frequency_range == FR1) + ssb_sc_offset_norm = ssb_subcarrier_offset>>scs_ssb; + else + ssb_sc_offset_norm = ssb_subcarrier_offset; if (mac->common_configuration_complete == 0) nr_ue_sib1_scheduler(module_id, cc_id, ssb_start_symbol, frame, - ssb_subcarrier_offset, + ssb_sc_offset_norm, ssb_index, ssb_start_subcarrier, mac->frequency_range, diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 5e99c2d0e1..ff4ec396e7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -344,21 +344,24 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); uint16_t sco = absolute_diff%(12*scs_scaling); // values of subcarrier offset larger than the limit only indicates CORESET for Type0-PDCCH CSS set is not present - uint8_t ssb_SubcarrierOffset_limit = 0; + int ssb_SubcarrierOffset_limit = 0; + int offset_scaling = 0; //15kHz if(frequency_range == FR1) { ssb_SubcarrierOffset_limit = 24; - } else { + if (ssb_SubcarrierOffsetssb_config.scs_common.value; + } else ssb_SubcarrierOffset_limit = 12; - } if (ssb_SubcarrierOffset>(cfg->ssb_config.scs_common.value))),"absoluteFrequencySSB has a subcarrier offset of %d while it should be %d\n",sco/scs_scaling,ssb_SubcarrierOffset); + AssertFatal(sco==(scs_scaling * ssb_SubcarrierOffset), + "absoluteFrequencySSB has a subcarrier offset of %d while it should be %d\n",sco/scs_scaling,ssb_SubcarrierOffset); cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG; cfg->num_tlv++; - cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset>>(cfg->ssb_config.scs_common.value); + cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset<ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index be33e4f688..44cdcef9fa 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -737,7 +737,7 @@ void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, nr_scs_e scs_common, nr_scs_e pdcch_scs, - nr_frequency_range_e freq_range, + frequency_range_t freq_range, uint8_t rmsi_pdcch_config, uint8_t ssb_idx, uint8_t k_ssb, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 399033abd0..27527edbcd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -222,7 +222,7 @@ void get_pdsch_to_harq_feedback(int Mod_idP, void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, nr_scs_e scs_common, nr_scs_e pdcch_scs, - nr_frequency_range_e freq_range, + frequency_range_t freq_range, uint8_t rmsi_pdcch_config, uint8_t ssb_idx, uint8_t k_ssb, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f516fc2219..8e8959c597 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -222,7 +222,15 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { mib->message.choice.mib->spare.size = 1; mib->message.choice.mib->spare.bits_unused = 7; // This makes a spare of 1 bits - mib->message.choice.mib->ssb_SubcarrierOffset = (configuration->ssb_SubcarrierOffset)&15; + AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); + int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; + frequency_range_t frequency_range = band<100?FR1:FR2; + int ssb_subcarrier_offset; + if(frequency_range == FR1) + ssb_subcarrier_offset = (configuration->ssb_SubcarrierOffset<24) ? (configuration->ssb_SubcarrierOffset<<*scc->ssbSubcarrierSpacing) : configuration->ssb_SubcarrierOffset; + else + ssb_subcarrier_offset = configuration->ssb_SubcarrierOffset; + mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset&15; /* * The SIB1 will be sent in this allocation (Type0-PDCCH) : 38.213, 13-4 Table and 38.213 13-11 to 13-14 tables @@ -236,7 +244,6 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { mib->message.choice.mib->pdcch_ConfigSIB1.searchSpaceZero = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero; } - AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); switch (*scc->ssbSubcarrierSpacing) { case NR_SubcarrierSpacing_kHz15: mib->message.choice.mib->subCarrierSpacingCommon = NR_MIB__subCarrierSpacingCommon_scs15or60; From 3d5fa54a4806473354c582db8bbd3274a79a674f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 2 May 2022 19:07:07 +0100 Subject: [PATCH 174/226] Fix logs in help of ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index b64b4c22c5..e537277f46 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -605,8 +605,8 @@ int main(int argc, char **argv) printf("-u Set the numerology\n"); printf("-w Start PRB for PUSCH\n"); //printf("-x Transmission mode (1,2,6 for the moment)\n"); - printf("-y Number of TX antennas used in eNB\n"); - printf("-z Number of RX antennas used in UE\n"); + printf("-y Number of TX antennas used at UE\n"); + printf("-z Number of RX antennas used at gNB\n"); printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); From b6a018089b8be24a793a620a0e4b7ff212edc3ae Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 2 May 2022 23:53:13 +0100 Subject: [PATCH 175/226] Fix in nr_ulsch_extract_rbs --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index b11423b083..6975eafee1 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -308,31 +308,26 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, unsigned char symbol, uint8_t is_dmrs_symbol, nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_DL_FRAME_PARMS *frame_parms) -{ + NR_DL_FRAME_PARMS *frame_parms) { unsigned short start_re, re, nb_re_pusch; unsigned char aarx, aatx; uint32_t rxF_ext_index = 0; uint32_t ul_ch0_ext_index = 0; uint32_t ul_ch0_index = 0; - //uint8_t k_prime; - //uint16_t n; int16_t *rxF,*rxF_ext; int *ul_ch0,*ul_ch0_ext; - //uint8_t delta = 0; int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; #ifdef DEBUG_RB_EXT - printf("--------------------symbol = %d-----------------------\n", symbol); printf("--------------------ch_ext_index = %d-----------------------\n", symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size); - #endif uint8_t is_data_re; start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB)%frame_parms->ofdm_symbol_size; nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; + #ifdef __AVX2__ int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); #else @@ -341,18 +336,13 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; - rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; + rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 if (is_dmrs_symbol == 0) { - // - //rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); if (start_re + nb_re_pusch <= frame_parms->ofdm_symbol_size) { - memcpy1((void*)rxF_ext, - (void*)&rxF[start_re*2], - nb_re_pusch*sizeof(int32_t)); - } - else { + memcpy1((void*)rxF_ext, (void*)&rxF[start_re*2], nb_re_pusch*sizeof(int32_t)); + } else { int neg_length = frame_parms->ofdm_symbol_size-start_re; int pos_length = nb_re_pusch-neg_length; memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t)); @@ -360,28 +350,23 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, } for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) { - ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t)); } - } - else { + + } else { for (aatx = 0; aatx < pusch_pdu->nrOfLayers; aatx++) { - ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + ul_ch0 = &pusch_vars->ul_ch_estimates[aatx*frame_parms->nb_antennas_rx+aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*nb_re_pusch2]; - //n = 0; - //k_prime = 0; rxF_ext_index = 0; ul_ch0_ext_index = 0; - ul_ch0_index = 0; - + ul_ch0_index = 0; for (re = 0; re < nb_re_pusch; re++) { - uint16_t k= start_re+re; - + uint16_t k = start_re + re; is_data_re = allowed_xlsch_re_in_dmrs_symbol(k, start_re, frame_parms->ofdm_symbol_size, pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type); - if (++k >= frame_parms->ofdm_symbol_size) { k -= frame_parms->ofdm_symbol_size; } @@ -390,9 +375,9 @@ void nr_ulsch_extract_rbs(int32_t **rxdataF, printf("re = %d, is_dmrs_symbol = %d, symbol = %d\n", re, is_dmrs_symbol, symbol); #endif - /* save only data and respective channel estimates */ + // save only data and respective channel estimates if (is_data_re == 1) { - if (aatx == aarx) { + if (aatx == 0) { rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); rxF_ext_index +=2; From e3fd9f7f8cdf907ef14a758e7cddb1e091160e5d Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 3 May 2022 00:29:44 +0100 Subject: [PATCH 176/226] To use the channel generated by multipath_channel() for single-layer case in ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 38 ++++++++++++++++-------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index e537277f46..fc4f916242 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1251,34 +1251,36 @@ int main(int argc, char **argv) } } - - if (UE2gNB->max_Doppler == 0) - multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); - else - multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); - - for (i=0; inb_antennas_rx; ap++) { - if (channel_model == AWGN) { - - double H_awgn_mimo[4][4] ={{1.0, 0.2, 0.1, 0.05}, //rx 0 - {0.2, 1.0, 0.2, 0.1}, //rx 1 - {0.1, 0.2, 1.0, 0.2}, //rx 2 - {0.05, 0.1, 0.2, 1.0}}; //rx 3 - + // The multipath_channel() function calculates a channel matrix with only 1's. So the channel rank is 1, and we + // cannot use multi-layer. To solve this issue, for now we use the H_awgn_mimo matrix for multi-layer. + if (precod_nbr_layers == 1) { + if (UE2gNB->max_Doppler == 0) { + multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials==1)?1:0); + } else { + multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, 2*slot_length, 0); + } + } else { + double H_awgn_mimo[4][4] ={{1.0, 0.2, 0.1, 0.05}, //rx 0 + {0.2, 1.0, 0.2, 0.1}, //rx 1 + {0.1, 0.2, 1.0, 0.2}, //rx 2 + {0.05, 0.1, 0.2, 1.0}}; //rx 3 + for (i=0; inb_antennas_rx; ap++) { // sum up signals from different Tx antennas r_re[ap][i] = 0; r_im[ap][i] = 0; - for (int aa=0; aanb_antennas_rx; ap++) { ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((r_re[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); - /* Add phase noise if enabled */ if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)], From 6db761692d56e56a137bb3ca9341b8130e84e8e0 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 3 May 2022 08:55:25 +0100 Subject: [PATCH 177/226] Remove update_pdsch_ps and update_pusch_ps flags to use_rrc_processing_timer instead --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 48 +++++++++++++++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 12 ++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 - 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 271d7c7f2a..e8230bc344 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -917,7 +917,7 @@ void pf_dl(module_id_t module_id, NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - if (ps->nrOfLayers != layers[UE_id] || ps->time_domain_allocation != tda || sched_ctrl->update_pdsch_ps) { + if (ps->nrOfLayers != layers[UE_id] || ps->time_domain_allocation != tda) { nr_set_pdsch_semi_static(sib1, scc, UE_info->CellGroup[UE_id], diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index d7478474b1..764c97e66f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -579,7 +579,11 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, bwpd = (NR_BWP_DownlinkDedicated_t*)bwpd0; } - if (sched_ctrl->update_pdsch_ps == true) { + // Prevent gNB to enable 256QAM table while the RRCProcessing timer is running. + // For example, after the RRC created RRC Reconfiguration message we need to prevent gNB to apply another MCS table + // before the RRC Reconfiguration being received by the UE, otherwise UE will not be able to decode PDSCH + // and the connection will drop. + if (sched_ctrl->rrc_processing_timer == 0) { if (bwpd && bwpd->pdsch_Config && bwpd->pdsch_Config->choice.setup && @@ -592,7 +596,6 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, } else { ps->mcsTableIdx = 0; } - sched_ctrl->update_pdsch_ps = false; } LOG_D(NR_MAC,"MCS Table Index: %d\n",ps->mcsTableIdx); @@ -2812,8 +2815,45 @@ void nr_mac_update_timers(module_id_t module_id, sched_ctrl->rrc_processing_timer--; if (sched_ctrl->rrc_processing_timer == 0) { LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %d\n", frame, slot, UE_id); - sched_ctrl->update_pdsch_ps = true; - sched_ctrl->update_pusch_ps = true; + + const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; + + NR_BWP_DownlinkDedicated_t *bwpd = UE_info->CellGroup[UE_id] && + UE_info->CellGroup[UE_id]->spCellConfig && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated ? + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; + + const uint8_t layers = set_dl_nrOfLayers(sched_ctrl); + const int tda = RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0][slot]; + nr_set_pdsch_semi_static(sib1, + scc, + UE_info->CellGroup[UE_id], + sched_ctrl->active_bwp, + bwpd, + tda >= 0 ? tda : sched_ctrl->pdsch_semi_static.time_domain_allocation, + layers, + sched_ctrl, + &sched_ctrl->pdsch_semi_static); + + NR_BWP_UplinkDedicated_t *ubwpd = UE_info->CellGroup[UE_id] && + UE_info->CellGroup[UE_id]->spCellConfig && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated && + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig ? + UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; + int dci_format = get_dci_format(sched_ctrl); + const int utda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + nr_set_pusch_semi_static(sib1, + scc, + sched_ctrl->active_ubwp, + ubwpd, + dci_format, + utda >= 0 ? utda : sched_ctrl->pusch_semi_static.time_domain_allocation, + num_dmrs_cdm_grps_no_data, + &sched_ctrl->pusch_semi_static); + } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index bbe135413b..5b2d9293f2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -988,8 +988,7 @@ bool allocate_ul_retransmission(module_id_t module_id, if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data - || sched_ctrl->update_pusch_ps) { + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { nr_set_pusch_semi_static(sib1, scc, sched_ctrl->active_ubwp, @@ -998,7 +997,6 @@ bool allocate_ul_retransmission(module_id_t module_id, tda, num_dmrs_cdm_grps_no_data, ps); - sched_ctrl->update_pusch_ps = false; } /* Check the resource is enough for retransmission */ @@ -1247,8 +1245,7 @@ void pf_ul(module_id_t module_id, const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data - || sched_ctrl->update_pusch_ps) { + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { nr_set_pusch_semi_static(sib1, scc, sched_ctrl->active_ubwp, @@ -1257,7 +1254,6 @@ void pf_ul(module_id_t module_id, tda, num_dmrs_cdm_grps_no_data, ps); - sched_ctrl->update_pusch_ps = false; } LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d\n", min_rb, rbStart); @@ -1385,8 +1381,7 @@ void pf_ul(module_id_t module_id, const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data - || sched_ctrl->update_pusch_ps) { + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { nr_set_pusch_semi_static(sib1, scc, sched_ctrl->active_ubwp, @@ -1395,7 +1390,6 @@ void pf_ul(module_id_t module_id, tda, num_dmrs_cdm_grps_no_data, ps); - sched_ctrl->update_pusch_ps = false; } update_ul_ue_R_Qm(sched_pusch, ps); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 54abee888b..fcc1e4c789 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -509,6 +509,7 @@ void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl); +int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl); void calculate_preferred_dl_tda(module_id_t module_id, const NR_BWP_Downlink_t *bwp); void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ubwp); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 31cdd96af0..f93090c3c1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -626,8 +626,6 @@ typedef struct { int ul_failure; struct CSI_Report CSI_report; bool SR; - bool update_pdsch_ps; - bool update_pusch_ps; bool set_mcs; /// information about every HARQ process NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; From 114dcc6a084224333c24e26628ea4b7753d7d949 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 3 May 2022 08:57:02 +0100 Subject: [PATCH 178/226] Remove irrelevant comment --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index ecc2ef0cff..7027e0336f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -346,7 +346,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output); } - // This updates the timers running at MAC layer nr_mac_update_timers(module_idP, frame, slot); // This schedules MIB From 2162ba6d82b365afc617f74c82f30ca6cde45323 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 3 May 2022 10:03:56 +0100 Subject: [PATCH 179/226] Fix sigma in ulsim --- openair1/SIMULATION/NR_PHY/ulsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index fc4f916242..c22ff82be6 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1237,7 +1237,9 @@ int main(int argc, char **argv) n_trials = 1; if (input_fd == NULL) { - sigma_dB = 10 * log10((double)txlev_sum * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; + // Justification of division by precod_nbr_layers: + // When the channel is the identity matrix, the results in terms of SNR should be almost equal for 2x2 and 4x4. + sigma_dB = 10 * log10((double)txlev_sum/precod_nbr_layers * ((double)frame_parms->ofdm_symbol_size/(12*nb_rb))) - SNR;; sigma = pow(10,sigma_dB/10); From 139d20a9ba68595338bc8ce353e3339c74aade50 Mon Sep 17 00:00:00 2001 From: Vijay Chadachan Date: Tue, 3 May 2022 11:58:15 +0200 Subject: [PATCH 180/226] Removing unused variables --- openair3/NAS/UE/EMM/Authentication.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index 36c90c4ab0..a2762d08e8 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -149,8 +149,7 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, int rc = RETURNerror; authentication_data_t *authentication_data = user->authentication_data; emm_timers_t *emm_timers = user->emm_data->emm_timers; - uint8_t nullRand[AUTH_CK_SIZE]; - memset(nullRand, 0, AUTH_CK_SIZE); + LOG_TRACE(INFO, "EMM-PROC - Authentication requested ksi type = %s, ksi = %d", native_ksi ? "native" : "mapped", ksi); /* 3GPP TS 24.301, section 5.4.2.1 From cfa37e721329932bdcb864ab940f3871342b35f6 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 3 May 2022 12:21:47 +0200 Subject: [PATCH 181/226] cosmetic changes --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 75 +++++++------------ openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 6 +- openair1/SIMULATION/NR_PHY/ulschsim.c | 2 - openair1/SIMULATION/NR_PHY/ulsim.c | 6 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 16 ++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 2 - .../NR_MAC_gNB/gNB_scheduler_primitives.c | 4 - 7 files changed, 35 insertions(+), 76 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 6975eafee1..5066316e62 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -478,17 +478,14 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, int off = 0; #endif - for (aatx = 0; aatx < nrOfLayers; aatx++) - { - for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) - { + for (aatx = 0; aatx < nrOfLayers; aatx++) { + for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { //clear average level avg128U = _mm_setzero_si128(); ul_ch128=(__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - for (rb = 0; rb < nb_rb_0; rb++) - { + for (rb = 0; rb < nb_rb_0; rb++) { avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[1], ul_ch128[1]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[2], ul_ch128[2]), x)); @@ -499,10 +496,9 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, ((int32_t*)&avg128U)[1] + ((int32_t*)&avg128U)[2] + ((int32_t*)&avg128U)[3]) / y; - } } - + _mm_empty(); _m_empty(); @@ -637,23 +633,19 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, QAM_amp128b = _mm_setzero_si128(); uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); - for (aatx=0; aatxnb_antennas_rx; aarx++) - { + for (aarx=0; aarxnb_antennas_rx; aarx++) { ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ul_ch_mag128 = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; ul_ch_mag128b = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; @@ -661,10 +653,8 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, rxdataF_comp128 = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aarx][symbol*(off+(nb_rb*12))]; - for (rb=0; rb2) - { + for (rb=0; rb2) { // get channel amplitude if not QPSK //print_shorts("ch:",(int16_t*)&ul_ch128[0]); @@ -1164,8 +1154,7 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, int off = 0; #endif - if (n_rx > 1) - { + if (n_rx > 1) { #if defined(__x86_64__) || defined(__i386__) for (int aatx=0; aatxnb_antennas_rx][(symbol*(nb_re + off))]; ul_ch_mag128b[0] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx][(symbol*(nb_re + off))]; - for (int aa=1;aa < n_rx;aa++) - { + for (int aa=1;aa < n_rx;aa++) { rxdataF_comp128[1] = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; ul_ch_mag128[1] = (__m128i *)&ul_ch_mag[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; ul_ch_mag128b[1] = (__m128i *)&ul_ch_magb[aatx*frame_parms->nb_antennas_rx+aa][(symbol*(nb_re + off))]; // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) - for (i=0; iulsch_channel_estimation_stats); - for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) - { + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag); - if (dmrs_symbol_flag == 1) - { + if (dmrs_symbol_flag == 1) { if (gNB->pusch_vars[ulsch_id]->dmrs_symbol == INVALID_VALUE) gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; - for (int nl=0; nlnrOfLayers; nl++) - { + for (int nl=0; nlnrOfLayers; nl++) { nr_pusch_channel_estimation(gNB, slot, @@ -1984,29 +1968,24 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, #endif uint32_t rxdataF_ext_offset = 0; - for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) - { + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; - if (dmrs_symbol_flag == 1) - { + if (dmrs_symbol_flag == 1) { if ((rel15_ul->ul_dmrs_symb_pos >> ((symbol + 1) % frame_parms->symbols_per_slot)) & 0x01) AssertFatal(1==0,"Double DMRS configuration is not yet supported\n"); gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; - if (rel15_ul->dmrs_config_type == 0) - { + if (rel15_ul->dmrs_config_type == 0) { // if no data in dmrs cdm group is 1 only even REs have no data // if no data in dmrs cdm group is 2 both odd and even REs have no data nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*6)); } - else - { + else { nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*4)); } } - else - { + else { nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; } @@ -2016,8 +1995,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, //---------------------------------------------------------- //--------------------- RBs extraction --------------------- //---------------------------------------------------------- - if (nb_re_pusch > 0) - { + if (nb_re_pusch > 0) { start_meas(&gNB->ulsch_rbs_extraction_stats); nr_ulsch_extract_rbs(gNB->common_vars.rxdataF, gNB->pusch_vars[ulsch_id], @@ -2104,8 +2082,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, nb_re_pusch); stop_meas(&gNB->ulsch_mrc_stats); - if (rel15_ul->transformPrecoder == transformPrecoder_enabled) - { + if (rel15_ul->transformPrecoder == transformPrecoder_enabled) { #ifdef __AVX2__ // For odd number of resource blocks need byte alignment to multiple of 8 int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); @@ -2123,8 +2100,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, //---------------------------------------------------------- /* In case PTRS is enabled then LLR will be calculated after PTRS symbols are processed * * otherwise LLR are calculated for each symbol based upon DMRS channel estimates only. */ - if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) - { + if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { start_meas(&gNB->ulsch_ptrs_processing_stats); nr_pusch_ptrs_processing(gNB, frame_parms, @@ -2143,8 +2119,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, /*-------------------- LLRs computation -------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------*/ start_meas(&gNB->ulsch_llr_stats); - for (aatx=0; aatx < rel15_ul->nrOfLayers; aatx++) - { + for (aatx=0; aatx < rel15_ul->nrOfLayers; aatx++) { nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aatx*frame_parms->nb_antennas_rx][symbol * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], gNB->pusch_vars[ulsch_id]->ul_ch_mag0[aatx*frame_parms->nb_antennas_rx], gNB->pusch_vars[ulsch_id]->ul_ch_magb0[aatx*frame_parms->nb_antennas_rx], diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 114d1a424b..8243d8b0c9 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -283,12 +283,10 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN); - + for(int i=0; i< ue->frame_parms.nb_antennas_tx; ++i) - { memset(ue->common_vars.txdataF[i], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size); - } - + LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); start_meas(&ue->phy_proc_tx); diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index d76d438446..1eaeb6139b 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -444,9 +444,7 @@ int main(int argc, char **argv) NR_UE_ULSCH_t *ulsch_ue = UE->ulsch[0][0]; if ((Nl==4)||(Nl==3)) - { nb_re_dmrs = nb_re_dmrs*2; - } mod_order = nr_get_Qm_ul(Imcs, 0); code_rate = nr_get_code_rate_ul(Imcs, 0); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index c22ff82be6..4d271b4d1d 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1359,8 +1359,7 @@ int main(int argc, char **argv) LOG_M("rxsigF0_llrlayers0.m","rxsF0_llrlayers0", &gNB->pusch_vars[0]->llr_layers[0][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); - if (precod_nbr_layers==2) - { + if (precod_nbr_layers==2) { LOG_M("rxsigF1_ext.m","rxsF1_ext", &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); @@ -1379,8 +1378,7 @@ int main(int argc, char **argv) } - if (precod_nbr_layers==4) - { + if (precod_nbr_layers==4) { LOG_M("rxsigF1_ext.m","rxsF1_ext", &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_M("rxsigF2_ext.m","rxsF2_ext", diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index c70044ddeb..3201b51d30 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -231,8 +231,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits - if (n_antenna_port == 4) - { // 4 antenna port and the higher layer parameter txConfig = codebook + if (n_antenna_port == 4) { // 4 antenna port and the higher layer parameter txConfig = codebook // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4 if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) @@ -259,8 +258,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1 if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) - && (*pusch_Config->maxRank == 1)) - { + && (*pusch_Config->maxRank == 1)) { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6]; @@ -279,11 +277,10 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con } } - if (n_antenna_port == 2) - { // 2 antenna port and the higher layer parameter txConfig = codebook + if (n_antenna_port == 2) { + // 2 antenna port and the higher layer parameter txConfig = codebook // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2 - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) - { + if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12]; pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13]; @@ -299,8 +296,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1 if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)) - && (*pusch_Config->maxRank == 1)) - { + && (*pusch_Config->maxRank == 1)) { if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) { pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 55bcec0de6..9df3a5e397 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -459,9 +459,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; uint8_t num_dmrs_cdm_grps_no_data = 1; if ((target_ul_Nl==4)||(target_ul_Nl==3)) - { num_dmrs_cdm_grps_no_data = 2; - } /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c40caa7316..d426bc69c7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1011,13 +1011,9 @@ void config_uldci(const NR_SIB1_t *sib1, } dci_pdu_rel15->precoding_information.val= 0; if (pusch_pdu->nrOfLayers == 2) - { dci_pdu_rel15->precoding_information.val = 4; - } else if (pusch_pdu->nrOfLayers == 4) - { dci_pdu_rel15->precoding_information.val = 11; - } // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports From 1e38cead3977fd34133d009883e16e7df0471253 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 6 Apr 2022 23:33:09 +0100 Subject: [PATCH 182/226] Increase MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER to allow gNB to work with 273PRBs and 256QAM at MCS 27 --- openair1/PHY/defs_nr_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index b24abd7de3..40c49cee17 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -85,7 +85,7 @@ #define NR_MAX_PDSCH_TBS 3824 #define NR_MAX_SIB_LENGTH 2976 // 3GPP TS 38.331 section 5.2.1 - The physical layer imposes a limit to the maximum size a SIB can take. The maximum SIB1 or SI message size is 2976 bits. -#define MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER 34 +#define MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER 36 #define MAX_NUM_NR_ULSCH_SEGMENTS 34 #define MAX_NR_ULSCH_PAYLOAD_BYTES (MAX_NUM_NR_ULSCH_SEGMENTS*1056) From 8641d54f4d91a927b03e0ae38d47b86e10cdf567 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 3 May 2022 15:56:18 +0100 Subject: [PATCH 183/226] Fix build after merge --- openair1/SIMULATION/NR_PHY/dlsim.c | 4 +- openair1/SIMULATION/NR_PHY/ulsim.c | 4 +- openair2/LAYER2/NR_MAC_gNB/config.c | 18 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 14 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 +- openair2/RRC/NR/rrc_gNB.c | 203 +++++------------- openair2/RRC/NR/rrc_gNB_nsa.c | 6 +- 7 files changed, 70 insertions(+), 182 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 57c702a409..3d510529ee 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -827,9 +827,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL, 0); + rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup, 0); + rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); // reset preprocessor to the one of DLSIM after it has been set during // rrc_mac_config_req_gNB gNB_mac->pre_processor_dl = nr_dlsim_preprocessor; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index e4c693d602..866fe8d486 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -751,9 +751,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL, 0); + rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup, 0); + rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup); frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 892237f3e0..9f7493e581 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -481,23 +481,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, NR_BCCH_DL_SCH_Message_t *sib1, int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup, - uint32_t rrc_reconfiguration_delay) { - - if (scc && rrc_reconfiguration_delay > 0) { - const int UE_id = find_nr_UE_id(Mod_idP,rnti); - if (UE_id >= 0) { - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->rrc_processing_timer == 0) { - const uint16_t sf_ahead = (uint16_t) ceil((float)6/(0x01<<(*scc->ssbSubcarrierSpacing))); - const uint16_t sl_ahead = sf_ahead * (0x01<<(*scc->ssbSubcarrierSpacing)); - sched_ctrl->rrc_processing_timer = (rrc_reconfiguration_delay << (*scc->ssbSubcarrierSpacing)) + sl_ahead; - LOG_I(NR_MAC, "Activating RRC processing timer for UE %d\n", UE_id); - } - } - return 0; - } + NR_CellGroupConfig_t *CellGroup) { if (scc != NULL ) { AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 0a5e7bc2dd..d15a4af9fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2847,13 +2847,16 @@ void nr_mac_update_timers(module_id_t module_id, NR_BWP_DownlinkDedicated_t *bwpd = spCellConfigDedicated ? spCellConfigDedicated->initialDownlinkBWP : NULL; const uint8_t layers = set_dl_nrOfLayers(sched_ctrl); - const int tda = RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0][slot]; + const int tda = sched_ctrl->active_bwp && RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] >= 0 ? + RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] : + (sched_ctrl->pdsch_semi_static.time_domain_allocation >= 0 ? sched_ctrl->pdsch_semi_static.time_domain_allocation : 0); + nr_set_pdsch_semi_static(sib1, scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, bwpd, - tda >= 0 ? tda : sched_ctrl->pdsch_semi_static.time_domain_allocation, + tda, layers, sched_ctrl, &sched_ctrl->pdsch_semi_static); @@ -2864,13 +2867,16 @@ void nr_mac_update_timers(module_id_t module_id, const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; int dci_format = get_dci_format(sched_ctrl); - const int utda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + const int utda = sched_ctrl->active_ubwp && RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] >= 0 ? + RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : + (sched_ctrl->pusch_semi_static.time_domain_allocation >= 0 ? sched_ctrl->pusch_semi_static.time_domain_allocation : 0); + nr_set_pusch_semi_static(sib1, scc, sched_ctrl->active_ubwp, ubwpd, dci_format, - utda >= 0 ? utda : sched_ctrl->pusch_semi_static.time_domain_allocation, + utda, num_dmrs_cdm_grps_no_data, &sched_ctrl->pusch_semi_static); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 4b46cb9a49..d400942680 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -62,8 +62,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, NR_BCCH_DL_SCH_Message_t *sib1, int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup, - uint32_t rrc_reconfiguration_delay); + NR_CellGroupConfig_t *CellGroup); void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c44b48ff83..1c480d2616 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -176,8 +176,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration rrc->carrier.siblock1, 0, 0, // WIP hardcoded rnti - NULL, - 0); + NULL); } /* set flag to indicate that cell information is configured. This is required @@ -287,8 +286,7 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, NULL, 0, ue_context_pP->ue_context.rnti, - cgc, - 0); + cgc); nr_rrc_rlc_config_asn1_req(ctxt_pP, ue_context_pP->ue_context.SRB_configList, @@ -484,8 +482,7 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( rrc_instance_p->carrier.siblock1, 0, ue_context_pP->ue_context.rnti, - NULL, - 0); + NULL); LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", @@ -741,29 +738,6 @@ rrc_gNB_generate_defaultRRCReconfiguration( LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - rrc->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - rrc->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - /* Free all NAS PDUs */ for (int i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -834,10 +808,16 @@ rrc_gNB_generate_defaultRRCReconfiguration( } if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP->ue_context.rnti, *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); + delay_ms); } } @@ -1037,29 +1017,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - rrc->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - rrc->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -1098,10 +1055,16 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( #endif if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP->ue_context.rnti, *rrc->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); + delay_ms); } } @@ -1240,29 +1203,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_pdusessions; i++) { if (ue_context_pP->ue_context.modify_pdusession[i].param.nas_pdu.buffer != NULL) { @@ -1301,10 +1241,16 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( #endif if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP->ue_context.rnti, *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); + delay_ms); } } @@ -1374,29 +1320,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - /* Free all NAS PDUs */ if (nas_length > 0) { /* Free the NAS PDU buffer and invalidate it */ @@ -1431,10 +1354,16 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( #endif if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP->ue_context.rnti, *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); + delay_ms); } } @@ -1511,8 +1440,7 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, 0, ue_context_pP->ue_context.rnti, - ue_context_pP->ue_context.masterCellGroup, - 0); + ue_context_pP->ue_context.masterCellGroup); LOG_D(NR_RRC,"Configuring RLC DRBs/SRBs for UE %x\n",ue_context_pP->ue_context.rnti); nr_rrc_rlc_config_asn1_req(ctxt_pP, SRB_configList, // NULL, @@ -1955,29 +1883,6 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_pdusessions; i++) { if (ue_context_pP->ue_context.pduSession[i].param.nas_pdu.buffer != NULL) { @@ -2020,10 +1925,16 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( } if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, ue_context_pP->ue_context.rnti, *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, - NR_RRC_RECONFIGURATION_DELAY_MS); + delay_ms); } } //----------------------------------------------------------------------------- @@ -2058,29 +1969,6 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP NULL, masterCellGroup); - if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - - uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && - ue_context_pP->ue_context.masterCellGroup->spCellConfig && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && - ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? - NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; - - rrc_mac_config_req_gNB(ctxt_pP->module_id, - 0, - RC.nrrrc[ctxt_pP->module_id]->configuration.pdsch_AntennaPorts, - 0, - 0, - 0, - RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - NULL, - delay_ms); - } - nr_rrc_data_req(ctxt_pP, DCCH, rrc_gNB_mui++, @@ -2089,6 +1977,19 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP buffer, PDCP_TRANSMISSION_MODE_CONTROL); + if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { + uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && + ue_context_pP->ue_context.masterCellGroup->spCellConfig && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated && + ue_context_pP->ue_context.masterCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList ? + NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_RECONFIGURATION_DELAY_MS; + + nr_mac_enable_ue_rrc_processing_timer(ctxt_pP->module_id, + ue_context_pP->ue_context.rnti, + *RC.nrrrc[ctxt_pP->module_id]->carrier.servingcellconfigcommon->ssbSubcarrierSpacing, + delay_ms); + } + return 0; } diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 4f4ebc7048..22d74faa98 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -359,8 +359,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, 1, // add_ue flag ue_context_p->ue_id_rnti, - ue_context_p->ue_context.secondaryCellGroup, - 0); + ue_context_p->ue_context.secondaryCellGroup); } else { rrc_mac_config_req_gNB(rrc->module_id, rrc->configuration.ssb_SubcarrierOffset, @@ -373,8 +372,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, 1, // add_ue flag ue_context_p->ue_id_rnti, - ue_context_p->ue_context.secondaryCellGroup, - 0); + ue_context_p->ue_context.secondaryCellGroup); } if(m == NULL){ From d059c717549e9e2e6d12b115fe441a3a8dce8a37 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 3 May 2022 16:08:18 +0100 Subject: [PATCH 184/226] Clean up and minor improvements in configuration files --- ...gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf | 19 ++++++------ ...gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf | 31 +++++-------------- ...gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf | 31 +++++-------------- 3 files changed, 26 insertions(+), 55 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf index c190e63baf..e3ecf87ca0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf @@ -21,17 +21,18 @@ gNBs = sd = 0x1; // 0 false, else true } ); - }); nr_cellid = 12345678L; ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts_N1 = 1; - pusch_AntennaPorts = 2; - ul_prbblacklist = "79,80,81,82" + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts_XP = 1; + pusch_AntennaPorts = 2; + do_CSIRS = 0; + ul_prbblacklist = "79,80,81,82" + pdcch_ConfigSIB1 = ( { controlResourceSetZero = 12; @@ -214,16 +215,16 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 100; + pucch0_dtx_threshold = 80; } ); RUs = ( { local_rf = "yes" - nb_tx = 2 - nb_rx = 2 - att_tx = 0 + nb_tx = 2; + nb_rx = 2; + att_tx = 0; att_rx = 0; bands = [78]; max_pdschReferenceSignalPower = -27; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf index 264ab137c0..763396998d 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf @@ -19,13 +19,8 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); - }); nr_cellid = 12345678L; @@ -33,10 +28,9 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_XP = 1; pusch_AntennaPorts = 2; -# do_CSIRS = 1; - min_rxtxtime = 2; + do_CSIRS = 0; ul_prbblacklist = "107,108,109,110" pdcch_ConfigSIB1 = ( @@ -244,8 +238,9 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 200; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; + pusch_FailureThres = 1000; ulsch_max_frame_inactivity = 0; } ); @@ -255,21 +250,20 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 120; + pucch0_dtx_threshold = 80; } ); RUs = ( { local_rf = "yes" - nb_tx = 2 - nb_rx = 2 - att_tx = 0 + nb_tx = 2; + nb_rx = 2; + att_tx = 0; att_rx = 0; bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 75; - sf_extension = 0; eNB_instances = [0]; ##beamforming 1x2 matrix: 1 layer x 2 antennas bf_weights = [0x00007fff, 0x0000]; @@ -316,21 +310,12 @@ security = { log_config : { global_log_level ="info"; - global_log_verbosity ="medium"; hw_log_level ="info"; - hw_log_verbosity ="medium"; phy_log_level ="info"; - phy_log_verbosity ="medium"; mac_log_level ="info"; - mac_log_verbosity ="high"; rlc_log_level ="info"; - rlc_log_verbosity ="medium"; pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; rrc_log_level ="info"; - rrc_log_verbosity ="medium"; ngap_log_level ="debug"; - ngap_log_verbosity ="medium"; f1ap_log_level ="debug"; - f1ap_log_verbosity ="medium"; }; \ No newline at end of file diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf index 7a1d087715..2a84743a0c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf @@ -19,13 +19,8 @@ gNBs = { sst = 1; sd = 0x1; // 0 false, else true - }, - { - sst = 1; - sd = 0x112233; // 0 false, else true } ); - }); nr_cellid = 12345678L; @@ -33,10 +28,9 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_XP = 1; pusch_AntennaPorts = 2; -# do_CSIRS = 1; - min_rxtxtime = 2; + do_CSIRS = 0; ul_prbblacklist = "135,136,137,138" pdcch_ConfigSIB1 = ( @@ -244,8 +238,9 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 200; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; + pusch_FailureThres = 1000; ulsch_max_frame_inactivity = 0; } ); @@ -255,21 +250,20 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 120; + pucch0_dtx_threshold = 80; } ); RUs = ( { local_rf = "yes" - nb_tx = 2 - nb_rx = 2 - att_tx = 0 + nb_tx = 2; + nb_rx = 2; + att_tx = 0; att_rx = 0; bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 75; - sf_extension = 0; eNB_instances = [0]; ##beamforming 1x2 matrix: 1 layer x 2 antennas bf_weights = [0x00007fff, 0x0000]; @@ -316,21 +310,12 @@ security = { log_config : { global_log_level ="info"; - global_log_verbosity ="medium"; hw_log_level ="info"; - hw_log_verbosity ="medium"; phy_log_level ="info"; - phy_log_verbosity ="medium"; mac_log_level ="info"; - mac_log_verbosity ="high"; rlc_log_level ="info"; - rlc_log_verbosity ="medium"; pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; rrc_log_level ="info"; - rrc_log_verbosity ="medium"; ngap_log_level ="debug"; - ngap_log_verbosity ="medium"; f1ap_log_level ="debug"; - f1ap_log_verbosity ="medium"; }; \ No newline at end of file From 7aa3bfaa54bc9e9c1d8d8d3033918c2d60a9e8d6 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 3 May 2022 18:25:57 +0100 Subject: [PATCH 185/226] Revert deleted rfdevice.trx_end_func() --- executables/nr-softmodem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index a9214535d3..7ec316ccd1 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -848,6 +848,9 @@ int main( int argc, char **argv ) { // *** Handle per CC_id openair0 for(ru_id=0; ru_idrfdevice.trx_end_func) + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + if (RC.ru[ru_id]->ifdevice.trx_end_func) RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); } From f2974b431b12f78274c175da04e090c07a13c89f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 3 May 2022 19:25:14 +0100 Subject: [PATCH 186/226] Revert transformPrecoder to transform_precoding --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 4 ++-- .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 2 +- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 10 +++++----- openair1/SIMULATION/NR_PHY/ulsim.c | 16 ++++++++-------- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 16 ++++++++-------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 ++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 12 files changed, 36 insertions(+), 36 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 01f3847bb2..fcc243f5cd 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -305,7 +305,7 @@ typedef struct uint8_t qam_mod_order; uint8_t mcs_index; uint8_t mcs_table; - uint8_t transformPrecoder; + uint8_t transform_precoding; uint16_t data_scrambling_id; uint8_t nrOfLayers; uint8_t Tpmi; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index cfa8022526..c3a173758c 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1210,7 +1210,7 @@ typedef struct uint8_t qam_mod_order; uint8_t mcs_index; uint8_t mcs_table; - uint8_t transformPrecoder; + uint8_t transform_precoding; uint16_t data_scrambling_id; uint8_t nrOfLayers; //DMRS diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 4d479da1b0..3adde23e7d 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -947,7 +947,7 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui push8(pusch_pdu->qam_mod_order, ppWritePackedMsg, end) && push8(pusch_pdu->mcs_index, ppWritePackedMsg, end) && push8(pusch_pdu->mcs_table, ppWritePackedMsg, end) && - push8(pusch_pdu->transformPrecoder, ppWritePackedMsg, end) && + push8(pusch_pdu->transform_precoding, ppWritePackedMsg, end) && push16(pusch_pdu->data_scrambling_id, ppWritePackedMsg, end) && push8(pusch_pdu->nrOfLayers, ppWritePackedMsg, end) && push16(pusch_pdu->ul_dmrs_symb_pos, ppWritePackedMsg, end) && @@ -4481,7 +4481,7 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(void *tlv, uint8_t **ppReadPacked pull8(ppReadPackedMsg, &pusch_pdu->qam_mod_order, end) && pull8(ppReadPackedMsg, &pusch_pdu->mcs_index, end) && pull8(ppReadPackedMsg, &pusch_pdu->mcs_table, end) && - pull8(ppReadPackedMsg, &pusch_pdu->transformPrecoder, end) && + pull8(ppReadPackedMsg, &pusch_pdu->transform_precoding, end) && pull16(ppReadPackedMsg, &pusch_pdu->data_scrambling_id, end) && pull8(ppReadPackedMsg, &pusch_pdu->nrOfLayers, end) && pull16(ppReadPackedMsg, &pusch_pdu->ul_dmrs_symb_pos, end) && diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 20575b45d1..9e2b3d2d4e 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -169,7 +169,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, gNB->pusch_gold_init[pusch_pdu->scid] = pusch_pdu->ul_dmrs_scrambling_id; nr_gold_pusch(gNB, pusch_pdu->scid, pusch_pdu->ul_dmrs_scrambling_id); } - if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { + if (pusch_pdu->transform_precoding == transformPrecoder_disabled) { nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], (1000+p), 0, nb_rb_pusch, (pusch_pdu->bwp_start + pusch_pdu->rb_start)*NR_NB_SC_PER_RB, pusch_pdu->dmrs_config_type); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 5066316e62..e81ef00cac 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -2082,7 +2082,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, nb_re_pusch); stop_meas(&gNB->ulsch_mrc_stats); - if (rel15_ul->transformPrecoder == transformPrecoder_enabled) { + if (rel15_ul->transform_precoding == transformPrecoder_enabled) { #ifdef __AVX2__ // For odd number of resource blocks need byte alignment to multiple of 8 int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index e4b6dbcc1d..450805a26c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -282,7 +282,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /// Transform-coded "y"-sequences (for definition see 38-211 V15.3.0 2018-09, subsection 6.3.1.4) int32_t y[max_num_re] __attribute__ ((aligned(16))); - if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { + if (pusch_pdu->transform_precoding == transformPrecoder_enabled) { uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; uint32_t y_offset = 0; @@ -377,7 +377,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, if ((ul_dmrs_symb_pos >> l) & 0x01) { is_dmrs_sym = 1; - if (pusch_pdu->transformPrecoder == transformPrecoder_disabled){ + if (pusch_pdu->transform_precoding == transformPrecoder_disabled){ if (dmrs_type == pusch_dmrs_type1) dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; @@ -393,7 +393,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, } } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - AssertFatal(pusch_pdu->transformPrecoder == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); + AssertFatal(pusch_pdu->transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { is_ptrs_sym = 1; @@ -424,7 +424,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, if (is_dmrs == 1) { // if transform precoding is enabled - if (pusch_pdu->transformPrecoder == transformPrecoder_enabled) { + if (pusch_pdu->transform_precoding == transformPrecoder_enabled) { ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; } else { @@ -448,7 +448,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; ptrs_idx++; } else if (!is_dmrs_sym || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { - if (pusch_pdu->transformPrecoder == transformPrecoder_disabled) { + if (pusch_pdu->transform_precoding == transformPrecoder_disabled) { ((int16_t*)tx_precoding[nl])[(sample_offsetF)<<1] = ((int16_t *)tx_layers[nl])[m<<1]; ((int16_t*)tx_precoding[nl])[((sample_offsetF)<<1) + 1] = ((int16_t *)tx_layers[nl])[(m<<1) + 1]; } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 4d271b4d1d..fc44e993bb 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -323,7 +323,7 @@ int main(int argc, char **argv) uint16_t ptrsSymbPerSlot = 0; uint16_t ptrsRePerSymb = 0; - uint8_t transformPrecoder = transformPrecoder_disabled; // 0 - ENABLE, 1 - DISABLE + uint8_t transform_precoding = transformPrecoder_disabled; // 0 - ENABLE, 1 - DISABLE uint8_t num_dmrs_cdm_grps_no_data = 1; uint8_t mcs_table = 0; @@ -581,10 +581,10 @@ int main(int argc, char **argv) break; case 'Z': - transformPrecoder = transformPrecoder_enabled; + transform_precoding = transformPrecoder_enabled; num_dmrs_cdm_grps_no_data = 2; mcs_table = 3; - printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transformPrecoder); + printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transform_precoding); break; default: @@ -879,7 +879,7 @@ int main(int argc, char **argv) if ((UE->frame_parms.nb_antennas_tx==4)&&(precod_nbr_layers==4)) num_dmrs_cdm_grps_no_data = 2; - if (transformPrecoder == transformPrecoder_enabled) { + if (transform_precoding == transformPrecoder_enabled) { AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); @@ -1084,7 +1084,7 @@ int main(int argc, char **argv) pusch_pdu->mcs_table = mcs_table; pusch_pdu->target_code_rate = code_rate; pusch_pdu->qam_mod_order = mod_order; - pusch_pdu->transformPrecoder = transformPrecoder; + pusch_pdu->transform_precoding = transform_precoding; pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = precod_nbr_layers; pusch_pdu->ul_dmrs_symb_pos = l_prime_mask; @@ -1111,7 +1111,7 @@ int main(int argc, char **argv) pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; // if transform precoding is enabled - if (transformPrecoder == transformPrecoder_enabled) { + if (transform_precoding == transformPrecoder_enabled) { pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; // U as defined in 38.211 section 6.4.1.1.1.2 pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; // V as defined in 38.211 section 6.4.1.1.1.2 @@ -1171,10 +1171,10 @@ int main(int argc, char **argv) ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t)); ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; - ul_config.ul_config_list[0].pusch_config_pdu.transformPrecoder = transformPrecoder; + ul_config.ul_config_list[0].pusch_config_pdu.transform_precoding = transform_precoding; // if transform precoding is enabled - if (transformPrecoder == transformPrecoder_enabled) { + if (transform_precoding == transformPrecoder_enabled) { ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_group_number = *scc->physCellId % 30;// U as defined in 38.211 section 6.4.1.1.1.2 ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;// V as defined in 38.211 section 6.4.1.1.1.2 diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 3201b51d30..868db25463 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -216,7 +216,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con else transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; } - pusch_config_pdu->transformPrecoder = transformPrecoder; + pusch_config_pdu->transform_precoding = transformPrecoder; /* PRECOD_NBR_LAYERS */ if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)); @@ -656,7 +656,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->scid = 0; // Transform precoding according to 6.1.3 UE procedure for applying transform precoding on PUSCH in 38.214 - pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out + pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, NULL, NR_RNTI_TC, 0); // TBR fix rnti and take out // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214 pusch_config_pdu->resource_alloc = (mac->cg) ? pusch_Config->resourceAllocation : 1; @@ -702,7 +702,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, /* Transform precoding */ if (rnti_type != NR_RNTI_CS || (rnti_type == NR_RNTI_CS && dci->ndi == 1)) { - pusch_config_pdu->transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); + pusch_config_pdu->transform_precoding = get_transformPrecoding(initialUplinkBWP, pusch_Config, NULL, dci_format, rnti_type, 0); } /*DCI format-related configuration*/ @@ -743,7 +743,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/ - if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) { + if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; @@ -796,7 +796,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->mcs_index = dci->mcs; /* MCS TABLE */ - if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_Table : NULL, 0, *dci_format, rnti_type, target_ss, false); } else { pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, 1, *dci_format, rnti_type, target_ss, false); @@ -831,12 +831,12 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + if (mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { if (*dci_format != NR_UL_DCI_FORMAT_0_1) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; } } - else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)) + else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[0] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; // Num PRB Overhead from PUSCH-ServingCellConfig @@ -857,7 +857,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup && mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB && mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { - if (pusch_config_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) { + if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { nfapi_nr_ue_ptrs_ports_t ptrs_ports_list; pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list; valid_ptrs_setup = set_ul_ptrs_values(mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index c9a22b92c2..9a651293b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1058,9 +1058,9 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->cyclic_prefix = 0; pusch_pdu->mcs_table = 0; if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) - pusch_pdu->transformPrecoder = 1; + pusch_pdu->transform_precoding = 1; else - pusch_pdu->transformPrecoder = 0; + pusch_pdu->transform_precoding = 0; pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = 1; pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index d426bc69c7..728948ba53 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -687,11 +687,11 @@ void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, ps->pusch_Config = ubwp && ubwp->bwp_Dedicated && ubwp->bwp_Dedicated->pusch_Config ? ubwp->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) - ps->transformPrecoder = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; + ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; else - ps->transformPrecoder = *ps->pusch_Config->transformPrecoder; + ps->transform_precoding = *ps->pusch_Config->transformPrecoder; const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - if (ps->transformPrecoder) + if (ps->transform_precoding) ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_Table : NULL, 0, ps->dci_format, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 4061590f6e..4fba22a0c0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1794,7 +1794,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->qam_mod_order = sched_pusch->Qm; pusch_pdu->mcs_index = sched_pusch->mcs; pusch_pdu->mcs_table = ps->mcs_table; - pusch_pdu->transformPrecoder = ps->transformPrecoder; + pusch_pdu->transform_precoding = ps->transform_precoding; if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; else @@ -1805,7 +1805,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* FAPI: DMRS */ pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos; pusch_pdu->dmrs_config_type = ps->dmrs_config_type; - if (pusch_pdu->transformPrecoder) { // transform precoding disabled + if (pusch_pdu->transform_precoding) { // transform precoding disabled long *scramblingid=NULL; if (ps->NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; @@ -1852,7 +1852,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); /* TRANSFORM PRECODING --------------------------------------------------------*/ - if (pusch_pdu->transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled){ + if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 4b55c70d1e..051f5927ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -350,7 +350,7 @@ typedef struct NR_pusch_semi_static_t { int nrOfSymbols; NR_PUSCH_Config_t *pusch_Config; - uint8_t transformPrecoder; + uint8_t transform_precoding; uint8_t mcs_table; long mapping_type; From 400b52b46f4dca7249acac482fe798ed04fd2237 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 May 2022 10:00:48 +0200 Subject: [PATCH 187/226] Do not separately install python for UHD, is done in general packages --- cmake_targets/tools/build_helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 554f3ccfe5..0d2c82d62e 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -410,7 +410,7 @@ check_install_usrp_uhd_driver(){ x=$((x + 1)) done $SUDO apt-get update - $SUDO apt-get -y install python python-tk libboost-all-dev libusb-1.0-0-dev + $SUDO apt-get -y install python-tk libboost-all-dev libusb-1.0-0-dev if [[ "$distribution" == "ubuntu16.04" ]]; then $SUDO apt-get -y install libuhd-dev libuhd3.15.0 uhd-host fi From cc6469c77d5766ac52c5116535cd6427fa3aa0e2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 May 2022 11:02:50 +0200 Subject: [PATCH 188/226] Upgrade SA test USRP IP address after CI migration --- .../conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf index 7b0e3eea22..18ca7b5d1e 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf @@ -260,7 +260,7 @@ RUs = ( ## beamforming 4x4 matrix: #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; sf_extension = 0 - sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + sdr_addrs = "mgmt_addr=172.21.19.14,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" sl_ahead = 5; } ); From 6d35883b2afca34e5b43743abfd922ab1855a960 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 May 2022 10:38:41 +0200 Subject: [PATCH 189/226] Add help strings for new config options --- openair2/ENB_APP/enb_paramdef.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 21e2e1b703..e6e97069fa 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -104,6 +104,11 @@ typedef enum { #define CONFIG_STRING_RU_NR_FLAG "nr_flag" #define CONFIG_STRING_RU_NR_SCS_FOR_RASTER "nr_scs_for_raster" +#define HLP_RU_SF_AHEAD "LTE TX processing advance" +#define HLP_RU_SL_AHEAD "NR TX processing advance" +#define HLP_RU_NR_FLAG "Use NR numerology (for AW2SORI)" +#define HLP_RU_NR_SCS_FOR_RASTER "NR SCS for raster (for AW2SORI)" + #define RU_LOCAL_IF_NAME_IDX 0 #define RU_LOCAL_ADDRESS_IDX 1 #define RU_REMOTE_ADDRESS_IDX 2 @@ -171,10 +176,10 @@ typedef enum { {CONFIG_STRING_RU_IF_FREQUENCY, NULL, 0, u64ptr:NULL, defuintval:0, TYPE_UINT64, 0}, \ {CONFIG_STRING_RU_IF_FREQ_OFFSET, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {CONFIG_STRING_RU_DO_PRECODING, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ - {CONFIG_STRING_RU_SF_AHEAD, NULL, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ - {CONFIG_STRING_RU_SL_AHEAD, NULL, 0, iptr:NULL, defintval:6, TYPE_INT, 0}, \ - {CONFIG_STRING_RU_NR_FLAG, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ - {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, NULL, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_SF_AHEAD, HLP_RU_SF_AHEAD, 0, iptr:NULL, defintval:4, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_SL_AHEAD, HLP_RU_SL_AHEAD, 0, iptr:NULL, defintval:6, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_NR_FLAG, HLP_RU_NR_FLAG, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ + {CONFIG_STRING_RU_NR_SCS_FOR_RASTER, HLP_RU_NR_SCS_FOR_RASTER, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ } /*---------------------------------------------------------------------------------------------------------------------------------------*/ From ada4be081caa14db2a9f83feea06324ac397ab67 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 May 2022 10:43:15 +0200 Subject: [PATCH 190/226] Remove clock_gettime() introduced in this branch --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +----- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 8 ++------ openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 9 ++------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7e4710ccda..f1eebfc026 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -456,14 +456,10 @@ int nr_process_mac_pdu(module_id_t module_idP, if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) return 0; - struct timespec time_request; - clock_gettime(CLOCK_REALTIME, &time_request); - LOG_D(NR_MAC, "[UE %04x] %d.%d : Time %lu.%lu ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", + LOG_D(NR_MAC, "[UE %x] %d.%d: ULSCH -> UL-%s %d (gNB %d, %d bytes)\n", UE_info->rnti[UE_id], frameP, slot, - time_request.tv_sec, - time_request.tv_nsec, rx_lcid<4?"DCCH":"DTCH", rx_lcid, module_idP, diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index ac7da5412b..b5cea6bdb9 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -711,9 +711,7 @@ rb_found: memblock = get_free_mem_block(size, __FUNCTION__); memcpy(memblock->data, buf, size); - struct timespec time_request; - clock_gettime(CLOCK_REALTIME, &time_request); - LOG_D(PDCP, "%s(): (rb %d) calling enqueue_rlc_data_req size %d at time %lu.%lu\n", __func__, rb_id, size,time_request.tv_sec,time_request.tv_nsec); + LOG_D(PDCP, "%s(): (srb %d) calling rlc_data_req size %d\n", __func__, rb_id, size); //for (i = 0; i < size; i++) printf(" %2.2x", (unsigned char)memblock->data[i]); //printf("\n"); enqueue_rlc_data_req(&ctxt, 0, MBMS_FLAG_NO, rb_id, sdu_id, 0, size, memblock); @@ -1338,9 +1336,7 @@ static boolean_t pdcp_data_req_drb( const sdu_size_t sdu_buffer_size, unsigned char *const sdu_buffer) { - struct timespec time_request; - clock_gettime(CLOCK_REALTIME, &time_request); - LOG_D(PDCP, "%s() called at time %lu.%lu, size %d\n", __func__, time_request.tv_sec,time_request.tv_nsec,sdu_buffer_size); + LOG_D(PDCP, "%s() called, size %d\n", __func__, sdu_buffer_size); nr_pdcp_ue_t *ue; nr_pdcp_entity_t *rb; int rnti = ctxt_pP->rnti; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 18ee7da8e2..baae1fa436 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -460,14 +460,9 @@ static void deliver_sdu(void *_ue, nr_rlc_entity_t *entity, char *buf, int size) exit(1); rb_found: - if (is_srb==0) { - struct timespec time_request; - clock_gettime(CLOCK_REALTIME, &time_request); + LOG_D(RLC, "%s:%d:%s: delivering SDU (rnti %d is_srb %d rb_id %d) size %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti, is_srb, rb_id, size); - LOG_D(RLC, "%s:%d:%s: delivering SDU Time %lu.%lu (rnti %d is_srb %d rb_id %d) size %d\n", - __FILE__, __LINE__, __FUNCTION__, time_request.tv_sec,time_request.tv_nsec, - ue->rnti, is_srb, rb_id, size); - } /* unused fields? */ ctx.instance = 0; ctx.frame = 0; From 65263a09ac1f6e714bcb47dd5a28dec6f1060898 Mon Sep 17 00:00:00 2001 From: Manish Date: Wed, 27 Apr 2022 05:31:12 +0000 Subject: [PATCH 191/226] help menu updated in document for native architecture. Compilation steps corrected on Ubuntu 20. Signed-off-by: Manish --- doc/BUILD.md | 1 + doc/TESTING_5GSA_setup.md | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index a52ce98cb5..70d69f5afd 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -193,6 +193,7 @@ Using the help option of the build script you can get the list of available opti | --UE | maintained and tested in CI | build `lte-uesoftmodem` the LTE UE | | --gNB | maintained and tested in CI | build `nr-softmodem` the 5G gNodeB | | --nrUE | maintained and tested in CI | build `nr-uesoftmodem` the 5G UE | +| --arch-native | maintained | build with native architecture optimization | | --usrp-recplay | deprecated | use the USRP configuration parameters to use the record player. | | --build-lib | maintained | build optional shared library(ies), which can then be loaded at run time via command line option. Use the --help option to get the list of supported optional libraries. `all` can be used to build all available optional libraries. | | --UE-conf-nvram | maintained | Specifies the path to the input file used by the conf2uedata utility. defaults to [openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf](../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf) | diff --git a/doc/TESTING_5GSA_setup.md b/doc/TESTING_5GSA_setup.md index 9b27549df4..4b86e12297 100644 --- a/doc/TESTING_5GSA_setup.md +++ b/doc/TESTING_5GSA_setup.md @@ -82,15 +82,7 @@ To get the code and build the gNB executable: git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git git checkout develop - # Install dependencies in Ubuntu 20.04 - cd - cd openairinterface5g/ - source oaienv - cd cmake_targets/ - ./install_external_packages.ubuntu20 - # Build OAI gNB - cd cd openairinterface5g/ source oaienv cd cmake_targets/ From 602fb113392b98f98fccbb99ccc37998a592c9c2 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 5 May 2022 13:39:04 +0100 Subject: [PATCH 192/226] Avoid usage of preferred_dl_tda and preferred_ul_tda before their computation and improve code readability --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 555c41a752..3f7a908395 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2829,42 +2829,52 @@ void nr_mac_update_timers(module_id_t module_id, const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; - NR_BWP_DownlinkDedicated_t *bwpd = UE_info->CellGroup[UE_id] && - UE_info->CellGroup[UE_id]->spCellConfig && - UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated ? - UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; + NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; + NR_BWP_DownlinkDedicated_t *bwpd = cg && + cg->spCellConfig && + cg->spCellConfig->spCellConfigDedicated ? + cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; + int **preferred_dl_tda = RC.nrmac[module_id]->preferred_dl_tda; + NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; const uint8_t layers = set_dl_nrOfLayers(sched_ctrl); - const int tda = RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0][slot]; + const int tda = bwp && preferred_dl_tda[bwp->bwp_Id][slot] >= 0 ? + preferred_dl_tda[bwp->bwp_Id][slot] : (ps->time_domain_allocation >= 0 ? ps->time_domain_allocation : 0); + nr_set_pdsch_semi_static(sib1, scc, - UE_info->CellGroup[UE_id], - sched_ctrl->active_bwp, + cg, + bwp, bwpd, - tda >= 0 ? tda : sched_ctrl->pdsch_semi_static.time_domain_allocation, + tda, layers, sched_ctrl, - &sched_ctrl->pdsch_semi_static); + ps); - NR_BWP_UplinkDedicated_t *ubwpd = UE_info->CellGroup[UE_id] && - UE_info->CellGroup[UE_id]->spCellConfig && - UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated && - UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig ? - UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + NR_BWP_Uplink_t *ubwp = sched_ctrl->active_ubwp; + NR_BWP_UplinkDedicated_t *ubwpd = cg && + cg->spCellConfig && + cg->spCellConfig->spCellConfigDedicated && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + int **preferred_ul_tda = RC.nrmac[module_id]->preferred_ul_tda; + NR_pusch_semi_static_t *ups = &sched_ctrl->pusch_semi_static; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; int dci_format = get_dci_format(sched_ctrl); - const int utda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; + const uint8_t num_dmrs_cdm_grps_no_data = (ubwp || ubwpd) ? 1 : 2; + const int utda = ubwp && preferred_ul_tda[ubwp->bwp_Id][slot] >= 0 ? + preferred_ul_tda[ubwp->bwp_Id][slot] : (ups->time_domain_allocation >= 0 ? ups->time_domain_allocation : 0); + nr_set_pusch_semi_static(sib1, scc, - sched_ctrl->active_ubwp, + ubwp, ubwpd, dci_format, - utda >= 0 ? utda : sched_ctrl->pusch_semi_static.time_domain_allocation, + utda, num_dmrs_cdm_grps_no_data, - &sched_ctrl->pusch_semi_static); - + ups); } } } From e1e8a49b763d313370a4499d92a100d540f81cce Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 5 May 2022 19:02:19 +0200 Subject: [PATCH 193/226] Fix UP traffic in NSA --- openair2/RRC/NR/rrc_gNB_nsa.c | 57 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 00e11278a2..b482637dfd 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -370,38 +370,37 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ue_context_p->ue_context.secondaryCellGroup); } - if(m == NULL){ - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_id_rnti, 0, 0, rrc->module_id); - LOG_W(RRC, "Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %x, frame %d, subframe %d eNB_index %d \n", &ctxt, - ctxt.module_id, - ctxt.rnti, - ctxt.frame, - ctxt.subframe, - ctxt.eNB_index); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_id_rnti, 0, 0, rrc->module_id); + LOG_W(RRC, + "Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %x, frame %d, subframe %d eNB_index %d \n", + &ctxt, + ctxt.module_id, + ctxt.rnti, + ctxt.frame, + ctxt.subframe, + ctxt.eNB_index); - nr_rrc_pdcp_config_asn1_req(&ctxt, - get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, - ue_context_p->ue_context.rb_config->drb_ToAddModList , - ue_context_p->ue_context.rb_config->drb_ToReleaseList, - (ue_context_p->ue_context.integrity_algorithm << 4) | ue_context_p->ue_context.ciphering_algorithm, - NULL, /* kRRCenc - unused */ - NULL, /* kRRCint - unused */ - kUPenc, /* kUPenc */ - kUPint, /* kUPint */ - NULL, - NULL, - ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); + nr_rrc_pdcp_config_asn1_req(&ctxt, + get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, + ue_context_p->ue_context.rb_config->drb_ToAddModList , + ue_context_p->ue_context.rb_config->drb_ToReleaseList, + (ue_context_p->ue_context.integrity_algorithm << 4) | ue_context_p->ue_context.ciphering_algorithm, + NULL, /* kRRCenc - unused */ + NULL, /* kRRCint - unused */ + kUPenc, /* kUPenc */ + kUPint, /* kUPint */ + NULL, + NULL, + ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); - nr_rrc_rlc_config_asn1_req (&ctxt, - get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, - ue_context_p->ue_context.rb_config->drb_ToAddModList, - ue_context_p->ue_context.rb_config->drb_ToReleaseList, - (LTE_PMCH_InfoList_r9_t *) NULL, - ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); - - LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti); - } + nr_rrc_rlc_config_asn1_req(&ctxt, + get_softmodem_params()->sa ? ue_context_p->ue_context.rb_config->srb_ToAddModList : (NR_SRB_ToAddModList_t *) NULL, + ue_context_p->ue_context.rb_config->drb_ToAddModList, + ue_context_p->ue_context.rb_config->drb_ToReleaseList, + (LTE_PMCH_InfoList_r9_t *) NULL, + ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); + LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti); } void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) { From eef8cf510b39ccc092b41679bfd0e00d1e6cf304 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 May 2022 11:17:49 +0200 Subject: [PATCH 194/226] Improve RFsim documentation --- targets/ARCH/rfsimulator/README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/targets/ARCH/rfsimulator/README.md b/targets/ARCH/rfsimulator/README.md index 4a8d5ff79a..feb7f015b9 100644 --- a/targets/ARCH/rfsimulator/README.md +++ b/targets/ARCH/rfsimulator/README.md @@ -61,6 +61,8 @@ Setting the env variable RFSIMULATOR can be used instead of using the serveraddr ## How to use the RF simulator options +To define and use a channel model, the configuration file needs to include a channel configuration file. To do this, add `@include "channelmod_rfsimu.conf"` to the end of the configuration file, and place the channel configuration file in the same directory. An example channel configuration file `channelmod_rfsimu.conf` is in `ci-scripts/conf_files`. + Add the following options to the command line to enable the channel model and the IQ samples saving for future replay: ```bash --rfsimulator.options chanmod,saviq @@ -82,6 +84,8 @@ Example run: sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test --rfsimulator.options chanmod --rfsimulator.modelname AWGN ``` +where `@include "channelmod_rfsimu.conf"` has been added at the end of the file, and `ci-scripts/conf_files/channelmod_rfsimu.conf` copied to `targets/PROJECTS/GENERIC-LTE-EPC/CONF/`. + ## 4G case For the UE, it should be set to the IP address of the eNB. For example: @@ -102,9 +106,7 @@ $OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurec ## 5G case -The 5G RF simulator will be aligned with the 4G as the efforts for merging the 5G specific branches into the develop make progresses. - -After regular build, add the simulation driver (do not use ./build_oai -w SIMU until 4G and 5G branches are merged). +If `build_oai` has not been run with `-w SIMU`, you need to build the `rfsimulator` manually. To do so: ```bash cd ran_build/build make rfsimulator @@ -113,7 +115,7 @@ make rfsimulator ### Launch gNB in one window ```bash -sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test +sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test --nokrnmod 1 ``` ### Launch UE in another window @@ -124,15 +126,17 @@ sudo RFSIMULATOR= ./nr-uesoftmodem --rfsim --phy-t Notes: -1. can be 127.0.0.1 if both gNB and nrUE executables run on the same host, OR the IP interface address of the remote host running the gNB executable, if the gNB and nrUE run on separate hosts -2. the --rrc_config_path parameter SHALL specify where the 2 RAW files are located (`rbconfig.raw` and `reconfig.raw`). +1. This starts the gNB and UE in the `phy-test` UP-only mode where the gNB is started as if a UE had already connected, and a configurable scheduler is used instead of the default one. The options `-m`, `-l`, `-t`, `-M`, `-T`, `-D`, and `-U` can be used to configure this scheduler. +2. can be 127.0.0.1 if both gNB and nrUE executables run on the same host, OR the IP interface address of the remote host running the gNB executable, if the gNB and nrUE run on separate hosts. +3. The --rrc_config_path parameter SHALL specify where the 2 RAW files are located (`rbconfig.raw` and `reconfig.raw`). - If you are running on the same machine and launched the 2 executables (`nr-softmodem` and `nr-uesoftmodem`) from the same directory, nothing has to be done. - If you launched the 2 executables from 2 different folders, just point to the location where you launched the `nr-softmodem`: * `sudo RFSIMULATOR= ./nr-uesoftmodem --rfsim --phy-test --rrc_config_path /the/path/where/you/launched/nr-softmodem` - If you are not running on the same machine or launched the 2 executables from 2 different folders, you need to **COPY** the 2 raw files * `scp usera@machineA:/the/path/where/you/launched/nr-softmodem/r*config.raw userb@machineB:/the/path/where/you/will/launch/nr-uesoftmodem/` * Obviously this operation SHALL be done before launching the `nr-uesoftmodem` executable. -3. to enable the noS1 mode --noS1 and --nokrnmod 1 options should be added to the command line +4. To enable the noS1 mode, `--noS1` option should be added to the command line. +5. To operate the gNB/UE with a 5GC, start them using the `--sa` option. More information can be found [here](../../../doc/TESTING_5GSA_setup.md#2-sa-setup-with-oai-nr-ue-softmodem). In the UE, you can add `-d` option to get the softscope. From d0de678f5613e8dcc09dc2108fa1be782bd3dc89 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 25 Apr 2022 17:23:05 +0200 Subject: [PATCH 195/226] Update CI documentation --- doc/TESTBenches.md | 229 ++++++++++++++++-- doc/testbenches_doc_resources/indoor_live.jpg | Bin 254133 -> 0 bytes doc/testbenches_doc_resources/legacy1.jpg | Bin 107882 -> 0 bytes doc/testbenches_doc_resources/legacy2.jpg | Bin 122055 -> 0 bytes doc/testbenches_doc_resources/next_ci.jpg | Bin 157592 -> 0 bytes doc/testbenches_doc_resources/next_dev.jpg | Bin 185772 -> 0 bytes .../outdoor_live.jpg | Bin 167702 -> 0 bytes 7 files changed, 204 insertions(+), 25 deletions(-) delete mode 100755 doc/testbenches_doc_resources/indoor_live.jpg delete mode 100755 doc/testbenches_doc_resources/legacy1.jpg delete mode 100755 doc/testbenches_doc_resources/legacy2.jpg delete mode 100755 doc/testbenches_doc_resources/next_ci.jpg delete mode 100755 doc/testbenches_doc_resources/next_dev.jpg delete mode 100755 doc/testbenches_doc_resources/outdoor_live.jpg diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 7365bc0f4c..fc05299110 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -1,45 +1,224 @@ ## Table of Contents ## -1. [Legacy 1 Bench](#legacy-1-bench) -2. [Legacy 2 Bench](#legacy-2-bench) -3. [Next Bench for DEV](#next-bench-for-dev) -4. [Next Bench for CI](#next-bench-for-ci) -5. [Indoor Live Network Bench](#indoor-live-network-bench) -6. [Outdoor Live Network Bench](#outdoor-live-network-bench) +1. [Machines](#machines) +2. [Networked devices](#networked-devices) +3. [Testbenches](#testbenches) +4. [Pipelines](#pipelines) +## Machines -## Legacy 1 Bench +| Machine | IP address | Lockable Resource | Function | Connected devices | +| ------------- | --------------- | --------------------- | ------------------ | ----------------------------------------------------- | +| asterix | 172.21.16.127 | CI-Asterix-Usage | gNB | 173.21.19.14 | +| obelix | 172.21.16.128 | CI-Obelix-Usage | eNB, UE (5G) | 172.21.19.13, X300 (192.168.60.2), B200mini (30C51EB) | +| porcepix | 172.21.16.136 | CI-NSA-MiniBench | Executor, EPC, 5GC | -- | +| nrmodule2 | 172.21.16.139 | CI-NSA-MiniBench | Quectel | Quectel module | +| nepes | 172.21.16.137 | CI-NSA-MiniBench | gNB | B200mini (30C51D4) | +| caracal | 172.21.16.132 | CI-Caracal | gNB/phytest | N300 (192.168.10.2) | +| idefix | 172.21.16.135 | CI-NSA-MiniBench | Quectel | Quectel module | +| amariue | 172.21.16.144 | CI-Amarisoft-UE-Usage | TBD | Amarisoft UE simulator | +| bellatrix | 192.168.117.115 | CI-RAN-VM-Deployment | Executor | -- | +| nano | 192.168.12.62 | CI-Bench-1-Phones | EPC, adb | 2x COTS (adb) | +| hutch | 192.168.12.19 | CI-Bench-1-Phones | eNB (B7) | B200mini (30C5239) | +| starsky | 192.168.12.18 | CI-Bench-1-Phones | eNB (B40) | b200mini (30A3E3C) | +| carabe | 192.168.12.211 | CI-Bench-2-OAI-Phone | UE 4G (B) | B200mini (30AE8C9) | -**Purpose** : FDD Band 7 and Band 13, LTE-M -**Note** : Legacy1 and Legacy2 are duplicated so that they can run in parallel, thus avoiding a CI bottleneck -**Note** : Faraday Cages 1 and 2 are physically the same cage +Note: The available resources, and their current usage, is indicated here: +- [Lockable resources of jenkins-oai](https://jenkins-oai.eurecom.fr/lockable-resources/): + "New" Jenkins, i.e., with RAN-Container-Parent +- [Lockable resources of open5glab jenkins](https://open5glab.eurecom.fr:8083/jenkins/lockable-resources/): + "Old" Jenkins, i.e., with RAN-CI-Develop -![image info](./testbenches_doc_resources/legacy1.jpg) +## Networked devices -## Legacy 2 Bench +| Type | IP address (mgmt) | +| ------------- | ----------------- | +| USRP N310 | 172.21.19.14 | +| USRP N310 | 172.21.19.13 | -**Purpose** : TDD Band 40, TM2 2xTX 2xRX -**Note** : CN can run in a container, could also run on Massive +## Testbenches -![image info](./testbenches_doc_resources/legacy2.jpg) +### OTA Testbench -## Next Bench for DEV +[Proper image to be followed up. TBD: add antennas/circulators] -**Note** : Benetel CI can also run on this bench at night +Note: obelix and porcepix are both used in the OTA testbench and the 5G +NSA/Faraday Cage testbench! -![image info](./testbenches_doc_resources/next_dev.jpg) +``` + asterix + ┌─────┐ ┌────┐ + │ ├────────┤N300│ + │ │ └────┘ + └─┬───┘ +porcepix │ +┌─────┐ │ nrmodule2 +│ ├───────────┘ ┌───────┐ ┌─────┐ +│ │ │Quectel├─────────┤ │ +└──┬─┬┘ obelix ┌────┐ └───────┘ │ │ + │ │ ┌─────┐ │N300│ └─────┘ + │ └──────────┤ ├────────┴────┘ + │ │ │ + │ └─────┴────────┬────┐ + │ │X300│ + │ └────┘ + │ UEsimbox + │ ┌─────┐ + └────────────┤ │ ┌────┐ + │ ├────────┤SDR │ + └─────┘ └────┘ +``` +### 5G NSA/Faraday Cage Testbench -## Next Bench for CI +**Purpose**: Faraday cage 5G tests -**Note** : The current test running on Caracal could run on this bench with a N300/N300 setup +Note: obelix and porcepix are both used in the OTA testbench and the 5G +NSA/Faraday Cage testbench! -![image info](./testbenches_doc_resources/next_ci.jpg) +[Proper image to be followed up] -## Indoor Live Network Bench +``` + obelix + ┌─────┐ + │ ├─────B7────────────────────┐ + │ │ Faraday Cage │ + └┬────┘ ┌──────────────┼───┐ + │ │ │ │ + │ │ Y │ +porcepix │ │ │ +┌─────┐ │ │ │ idefix +│ ├──────┘ │ Y──┼────┐ ┌─────┐ +│ │ │ Y--│----├───────┐ │ │ +└────┬┘ │ Y──┼────┤Quectel├──────┤ │ + │ │ Y--│----└───────┘ └─────┘ + │ │ Y │ + │ nepes │ │ │ + │ ┌─────┐ └────────────┼─────┘ + │ │ │ │ + └──────┤ ├─────B78─────────────────┘ + └─────┘ +``` -![image info](./testbenches_doc_resources/indoor_live.jpg) +### 4G Testbench(es) -## Outdoor Live Network Bench +**Purpose**: 4G/LTE testbenches -![image info](./testbenches_doc_resources/outdoor_live.jpg) +[Proper image to be followed up] + +``` + hutch + ┌─────┐ + │ ├─────B7────────────────────┐ + ┌──────┤ │ Faraday Cage │ + │ └─────┘ ┌──────────────┼───┐ + │ │ │ │ + │ │ Y │ +nano │ │ │ +┌────┴┐ USB ┌──┼─UE │ carabe +│ ├─────────────────────┤ │ │ ┌─────┐ +│ │ └──┼─UE │ │ │ +└───┬─┘ │ Y──┼───────B7UE──┤ │ + │ │ │ └─────┘ + │ │ Y │ + │ starsky │ │ │ + │ ┌─────┐ └────────────┼─────┘ + └───────┤ │ │ + │ ├──┬───────B40────────────┘ + └─────┘ │ + Y (sniffer) +``` + +## Pipelines + +### [RAN-Container-Parent](https://jenkins-oai.eurecom.fr/job/RAN-Container-Parent/) + +**Purpose**: automatically triggered tests on MR creation or push, from Gitlab +Webhook + +- [RAN-cppcheck](https://jenkins-oai.eurecom.fr/job/RAN-cppcheck/1664/) + - obelix + - performs static code analysis, currently not actively enforced +- [RAN-gNB-nrUE-MONO-TDD-Band78-N300](https://jenkins-oai.eurecom.fr/job/RAN-gNB-nrUE-MONO-TDD-Band78-N300/) + - caracal + N310 + - pure performance test through phy-test scheduler, see command line for more + details +- [RAN-L2-Sim-Test-5G](https://jenkins-oai.eurecom.fr/job/RAN-L2-Sim-Test-5G/) + - obelix (gNB, 1x UE, OAI 5GC) + - L2simulator: skips physical layer and uses proxy between gNB and UE, + currently only ping +- [RAN-NSA-B200-Module-LTEBOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-NSA-B200-Module-LTEBOX-Container/) + - obelix + B200, nepes + B200, idefix + Quectel, porcepix w/ ltebox + - basic NSA test, known to be instable +- [RAN-PhySim-Cluster](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster/) + - asterix (`Asterix-OC-oaicicd-session` resource), tests in OpenShift Cluster + - unitary simulators (`nr_dlsim`, etc.) +- [RAN-RF-Sim-Test-4G](https://jenkins-oai.eurecom.fr/job/RAN-RF-Sim-Test-4G/) + - obelix (eNB, 1x UE, OAI EPC) + - uses RFsimulator, for FDD 5, 10, 20MHz with core, 5MHz noS1 +- [RAN-RF-Sim-Test-5G](https://jenkins-oai.eurecom.fr/job/RAN-RF-Sim-Test-5G/) + - obelix (gNB, 2x UE, OAI 5GC) + - uses RFsimulator, TDD 40MHz, FDD 40MHz, F1 split +- [RAN-RHEL8-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-RHEL8-Image-Builder/) + - asterix: RHEL 8 image build using podman +- [RAN-Ubuntu18-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu18-Image-Builder/) + - obelix: Ubuntu 18 image build using docker + +### [RAN-CI-NSA-Trigger](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-CI-NSA-Trigger/) + +**Purpose**: longer-running over-the-air LTE, NSA, and SA tests, triggered +through cron job at midnight + +- [RAN-LTE-2x2-Module-OAIEPC](https://jenkins-oai.eurecom.fr/job/RAN-LTE-2x2-Module-OAIEPC/) + - obelix + N310, nrmodule2 + Quectel, porcepix w/ Magma EPC + - LTE 2x2 test with TM1 and TM2 +- [RAN-NSA-B200-Module-LTEBOX](https://jenkins-oai.eurecom.fr/job/RAN-NSA-B200-Module-LTEBOX/) + - obelix + B200 (eNB), nepes + B200 (gNB), idefix + Quectel, porcepix w/ ltebox + - Note: like [RAN-NSA-B200-Module-LTEBOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-NSA-B200-Module-LTEBOX-Container/) above, but compiled/run from source +- [RAN-NSA-2x2-Module-OAIEPC](https://jenkins-oai.eurecom.fr/job/RAN-NSA-2x2-Module-OAIEPC/) + - obelix + N310 (eNB), asterix + N310 (gNB), nrmodule2 + Quectel, porcepix w/ Magma EPC + - LTE 2x2 and NR 2x2 (non-standalone) +- [RAN-SA-Module-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-Module-CN5G/) + - asterix + N310 (gNB), nrmodule2 + Quectel, porcepix w/ OAI 5GC + - NR 2x2 (standalone) +- [RAN-SA-OAIUE-N310-X300-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-OAIUE-N310-X300-CN5G/) + - asterix + N310 (gNB), obelix + N310 or X300 (5G UE), porcepix w/ OAI 5GC + - OTA test with OAIUE using both N310 and X300 +- [RAN-SA-AmariS-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-AmariS-CN5G/) + - asterix + N310, amariue (1x UE), porcepix w/ OAI 5GC + - Amarisoft UE simulator: expected to be increased to more UEs + +### [RAN-CI-develop](https://open5glab.eurecom.fr:8083/jenkins/job/RAN-CI-develop/) + +**Purpose**: automatically triggered tests, mostly 4G, to be phased out and +integrated into RAN-Container-Parent + +runs tests: +- bellatrix: runs 4G/5G simulators directly (eNB + 1x UE + (opt.) OAI EPC, gNB + 1x UE in "noS1") + +triggers pipelines: +- [eNB-CI-F1-FDD-Band7-B210](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-CI-F1-FDD-Band7-B210/) + - hutch + B210, nano w/ ltebox + 2x UE + - tests 4G FDD with F1 split, 5MHz, 10MHz, 20MHz. 5MHz stable, rest known to + be unstable +- [eNB-CI-FDD-Band7-B210](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-CI-FDD-Band7-B210/) + - hutch + B210, nano w/ ltebox + 2x UE + - tests T tracer, information through FlexRAN, RRC inactivity timers, + inactivity timers + FlexRAN, different bandwidths +- [eNB-CI-IF4p5-FDD-Band7-B210](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-CI-IF4p5-FDD-Band7-B210/) + - hutch + B210, nano w/ ltebox + 2x UE + - tests IF4.5 split over bandwidths 5, 10, 20 MHz in Band 7 +- [eNB-CI-IF4p5-TDD-Band40-B210](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-CI-IF4p5-TDD-Band40-B210/) + - starsky + B210, nano w/ ltebox + 2x UE + - tests IF4.5 split over bandwidths 5, 10, 20 MHz in Band 40 +- [eNB-CI-TDD-Band40-B210](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-CI-TDD-Band40-B210/) + - starsky + B210, nano w/ ltebox + 2x UE + - T tracer, TM1 over bandwidths 5, 10, 20 MHz in Band 40, default scheduler + for 20 MHz +- [eNB-UE-CI-MONO-FDD-Band7-B200](https://open5glab.eurecom.fr:8083/jenkins/job/eNB-UE-CI-MONO-FDD-Band7-B200/) + - hutch + B210 (eNB), carabe + B210 (4G UE), nano w/ ltebox + - tests OAI 4G for 5 MHz/TM1 with both CN and in noS1 model, MBMS; known to + be unstable +- [UE-CI-FDD-Band20-B200](https://open5glab.eurecom.fr:8083/jenkins/job/UE-CI-FDD-Band20-B200/) + - starsky + B210 (sniffer) + - Sniff MIB + SIB1 of Orange, SFR diff --git a/doc/testbenches_doc_resources/indoor_live.jpg b/doc/testbenches_doc_resources/indoor_live.jpg deleted file mode 100755 index ce8b9cda4817796abf6fb87da43befe6090469be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254133 zcmeFa2UJvBwl2JpB%lNZBo`6{2`Wi41u7sQl0mXcrbI-dq#_7NP6CP~$w-!*K{5(R z&N)f0A{J0o{Tt6Y-F^Dr`(FQVbdUGO8RFPO%i643Ywb1DH@`UxJBpnJ$Q9)jc|6m&dit_|^ z7ld(fSb%dBIJguz*cJc+066&IY|keA`wz}JTs(XN!t+GLB;XBY2pbGS$RceRrQzVme#iRj?S+Bfx)5Sk;G3aBHfp1$lOre+hIV@IAX?dQt=wT1coAFb?f3;X-J#(@jC zIN-y>r2wG7;W1~b7xAy_-?#^Pr;cM1k~!6U+WHFjAHR?pwaRdQB5Z1@X3%dL|0-0$ zYljeBYKzQ*KUtmG-GXl~z(bAM+^~SLOF>Uq&R0EEtkUK>)RwHA5*KgH+cUx_Wy7T z7TDkw{^RpcNRgVcmF<@?qhD;6T*M^MNHEGd}R^~%(P(vI#H9E zb06ocaJQ;#_(TeU~Vqhhw`6UYf_W~8$re}>=2c;5F2K1yft`xpXy)ca(w`camuGN;CV zF57gSX+DUYG>~NrX5Ba^VIjiN(4X*haifBuU&lP3suljF3zYw^Z7jeD%74|9g;Tnn zCzSOzIUG2dxVFng?F;%6LZ$`t=D8Xk4?hJFva&|N!mCk%S$b35&xhk4^od_(eNIHk zRF-i4VP>Qbmqv)QII-S*Kueu~#MqSg#uYRyqu;USqBSmW$lSr{9_xh$H7zkJ=0Y}# z93t^+mTJ0E%p-G%{dDKcciB?qN6%4=&~ESLlqwtX+AHgirn(HhD;Q~W$v$|wv{LT7 zY%p1;On05Ak?o*B=RR^Msqj{x&AsF!Vi;t98hT0@RvONK#MziLO;&4My@7cVn{>tQQ<26 zuU#F}>QYM}xAd>jZuctsKJYQV0&8-Ve884RKtgIjHmCO884KVVy?!F16{DauCCZS- z$;qDc14Ehw3nzY5yBJ5@MYM%W4wdHaDMhhVArGS^U~DR{m`&{>UP;QjZszA{I~D6o z*E|h8$J{H;-NxirV@usD6k@KFULDcqO>)VZsX70NpZiYsaGX#J^nl z{MY2Szi8i&xUNoU#NAtqFVW{xFvZGY`e~i{U|ePQT(lnYW*~>x*xEUzM~is;udeYg zAXlhHQ1s2iPEKi>;P~;Tsyo_-N=)Z)~5vA^Y=ILS&cOmkFR{Q6f=`f3l;uz5G5MZ9eJXVie6eg9SzgKuKZVB* zdI<|Gl30PkA>`zG!FaK|^4vD+e%{lHD^Lr*&gJJjhZa73gRaA)ud=n&W7`~`E)hh^ z&tU;{5E$f)=wKXMQ3DTb=v$I4%b5)9=PiRmY@Q5~wI{dLaWo%852&MJrQpeB?<+PY zMkcPMAa4e+AQ=->OQ-J@OD)EkZ{Q9(GB81}>JPNY(FEN5{B1>{E6PyK_TJ!#PG5eZ z4sE2=3-McX0W0yl7dbGBEbx(yH{urwZw<=@YxUDF8aMB@WnXN$`|ZsF2WvJ& zt<^4>)Dd1{9cA@dcx%gl@!$nCyLXX$5Ecj_!xI~y8DBF}#D(d6(n_!ellr#Ur6vP-%2cC>LYLzsS72mm9en0y8YqRi=yJ_Z-MF0 zuHymH99gW;P*;Xxc|jG*>_Yk+ZEadSrj!wi9Cx9zBztzh1$}OYcT>XNd!l%rr9XzU zxE{tROSGzA)>!fW4)bImD9t5Gn7Ye$LKa6{$E$=T4mZbisHzr#w5X-jo?l@X`C_^scqw-Yo z%ZK*rQJ-bkI8!T0BQkz!$yhJqj~Va|okv)p05pz2(sTFkDq(?$0`S2bg2uB?L9-k_ zq9)mwFH5OyhEJ&`{pwg^@pJAJ;tZN(B1hv zvEM-97~=S@kps%aCzX_}Apnfem@mct1a9;IMLo`xb3uA%2!@_CJMUR2#!Gp23-H?u z%2FUk{?9U{v*r&vu~!XEFg5L1AT=uI87O|KZfV*ve$-i%Iu5nfVi z<8}TO`7#3`W**<>G!n~3IkRnVq!oWo+In{M;-gdJ3ZN6Sp2R)u`1Mt0X_&qtKQ&H> zX-JgI^=SCe? zdYK-l#s+m1{Wg&^i3ewucX|_ZXZ(+d#8TVyJt);Se@J!w7-&Q99m?fXs+~bPXFB26 z^=l9QI%h!pA5GeVyJ|N!AI<(S{V?v{He9iGjt!B zlDh^iOW0q~#tRR#^r;eAW=t|XOWqx6?zp&`P92T$pFJQ53 zpp3(-uMb9^Imw5zVrRnM|1-1sN2DpC(e~-<{Q7B^+_E~qSZHb~7ML?zhwrwvV@@lu z0F_a(th2{UQZ50%%@r&FEFWA_uIw5S&1Y@75;skntP@Mq-D1Vf#S)QUA+jC6duq~l zoK%t7X=0C`dT;TPiQL7eUMHcAL2ZZiFPB~}u4hHsXI$sDXJSloNjhv!wmf0b-d@?9 zTH$7}>EZK{RCYZKD7(JzK`@M&XAjbS8>@v!N)r-tAkw>_=b+y5lvPKIUTRJ;IzT@K zT)@(8VonfO{<)M4&_C_|NBP%|F<))iq5eHH!<(V4mZkckC4jQ?(Lxw;47i#Pw- z-oE{1Z-3=H|4KQ}Ki2ZE*xPHr+1tI*v$**rHSsP`U}1pFkM+ww4RV78GBCe1X%jt; zUtO0vywkr=i$3{EV;=W>sz>Zn7u(sMG?X& z%@#&{mw2MHjQsHhADAD?IZM}CcqG>iM!6Q5qsHRv8{ZQnb|c}Fg5`USguyh*LorUz zYgS~;y1WJR8fY_3?<0m0tt@LNy|SXp;!1_IABy{g-@{T)VGs?3RA9FLXL;-L&kKuD zI2DAG4niw*TAL%UCDi-6T6kW*(jgWTbHxH`4+Skpf)8|*9SGGO##cu7>nyYb?)5J= zBr-1C!O?7c_)vU=7o7avpOf!Bo4ouyp%hsa>j@H!S?*MA2k6NqXRnTgyP4r_M0sW2 z!}AV`7hH8CR8Or>OIXmZc;=&wNM&rcCGeRRYD#5<;mG_>HO)o?k2`lMH9WJo;2_ zOliaRmUkg7enkDgT^^u)rNzXpY7l02wIyKosBdNlD!a?<#X}z zI);D1fe7!?cG6WvKPwom9$I=zZ#rK^Pg|&#{#WqpIZI< zr^24c2IGW(T+_=NAI`|M&g`5XKYvYu*TfX>z8N0*w<(E+;cDU)!QLZ?Q13C~Gnf$A zf~Doq`~t21I-u463(xX@51e&^xz{ro+ymq`DPVqN{Y)z1EE`k87q4c4Ir(cC#|e}P zM%F_BQx|=tLxGgX+@XV?zO-F2Z1;yQ>I^{F$DlFJ+E~ERyITd-f4Kz<>~OEa_cyRW zS7o?g!w$tDbUg|Sh;2!zfK-BVa8RRObZ#$(!B}^6##m@-kb13;Q$x@jXQkZgyYifQ zgr-ye<)PeGcjs`_gZ&Gx?O@_+xK2P785WQ=A=qH+Ki57LHq{&}mGD9;v$kEivum7kdvhT8_z+NNOBO1jIF$&z=m)}H1sfMk<7Yt_*-nX~w-q`PVe1ed`7q7rU zeH(!B)oUOZK{$3mX2P++9V&0cjCxV=fUWk<@%U8yV@+kQkF1QJtsf^8MODCe7)lH3 z$m9!2t9#KL_UDnwo3|%Gmby#fgW+1cbgS~`!-r~ylQB{TFUseVUy7WoyotA}v2Jut zY0Otpd*{_ohglT zsJ~34dEB_^nw;V`PQW0OEJ()KSC(4t8SWvPk6*nuJ#pS9xODOIgeZfXPL^Np4M*iK zGrpqSGB0;?7?T6`C81jVEOE-J5zIU2yvJ?QC+RxLXgQmUWw?u1#IhUXy4reX;HP=6 zo#>;Xj_sF5r^V|1@Zm)zQ zj(T{oR6|#(<7(;l26w|I5$lP-y{6C2Nh0kH8LtYPWg}1-?{P+XXI?S#MTU=1K7>E| zcwOkZaV0CnOpQIi*9ZhqcEY~r)rn*79RHCwvDP+9{72jSNgTTV34~L@@b3PXptDrV zf8eSj!v{mmxHM3fKEb)x*CP?e=s;KKscY8Gr#J6wlw^5Tsg~?7&nOuhOBh@Zh`}PqhXoyE%8y{aD>DLoRd+lL?;{))t%1{>I=dgv*j4LpzU5Wbk zf^gwMMNN5)HVpPAQ%mHU@Wt@1O50HQj-sROVG78v=rn+AOkn{C6B`zAnmFo|-N&5~ zyO88lyo7Z2PpLg&n`Z7$tD36lf^{_Gj+%(}3eCfrYOOqlG7xp419z<`akhqqm$g0b zRJh|ewR=n+WUWF=YUASBbcEwU{^TnOE0(s{iGGQYh=;TK6%S0NV;YaoiC%g%e1FQ2 z#*{z77d60E>2nFMM4nc{>l^;7kuQa~uq6E2;k+{XjH-bp^0Kt{tD`Et4T};vCsq3k z(P0v~2VPhpDil(7w)(yoQtwV2lhLP5pwQtzQl~k0o_UX@-o^L8sj7P5Np(O=#CAM; z1nW3Cft+2$%8}01xtYtTfH~)o3FVr~w|Wx>ubj)>4&~OT-a3hhd(%itwqC(qe|pD9 z0U%8ugggfchsl-D?b$rY8yhS@J=4OI<(u`j0}D8ed}|=}WU6SPUtc#H^a~$*sw+$* z(LE;8K24K4>)}R;=uYO+jAnGYCB*LjaRKUI&x|rHKdvkIWL9CZ(>nFh#Wb+zAt@QK zPym~dB6C?@Z%d+iXZ;{F=h1zZ_ai_@x|u;(%UnR#*W||rWcR@2AJ7bf5bh(;^)H|U zbGND>tZGUaBj0V0spVrM|6$=pY9P9+ol+b7vNaP=N9tTYh@HCV-)ac(7__o9H=x~9) zNNk}@KO>(}SA&-UIX~73!Sb!aVBDUws zl{3$!uI*ctr6_=kY|?kXQT%{DU+&e5R}?AIaETG)j2{PLLWN@+Hp6TjJgy}Wb(L#{ zeTo^bF@n+O2VOhLnKz^r)TDK1m9{}{`7qqrAh++YY(Qy2_vx@er!l6djw#3iNoAEQ zGpdn6RMW}8oAu@N_BHM5+R9``Eoo`^`%~EG;(<+vulLGIyr1}qabW>|w`6;5%MA50 z#bo-*g@=47RSot)4!`+GXVx5Trj-30&b$KM73XB)d8=SuYa0d&6nnTGJjsbi)sk;r1aRm-o@!rKz9&tiBlZxyEtXMU}|M%Of(C7rqU}nZKGK zgdS5l#S;ebNQhha>2V8GeT!E3Dx5Vd$!!$$>0NvoRr($!=NHmdkX!YL4&Mw6w6FZ0 zP~cYo4A%0Itp8pHqIO0rP)+(Vm>R_OAJaHgoi5y%d-)JdoyL)lzCp52!=mEvk*7%D zhtkqgEu3A#|7r!nl+JHfkZRX?6UgvnX}RBMBgG<#v4Hf~`y)cpu35gNupf;iLT?{v z-rmfz?C34-Kwo#njYExK0k$;IUv(urWr%6Qbk87>^D2in4GA%m?k_6+A%4}bU*7+; z`<3`!`fLpmRgt8NI-Ga`YQFyJ4k~EzBYAN}sQysEyZdMyNFt+jE^?*ua5I;T>d^#k zz7dsDFE77|*{rxpvB8CdiM_mDJa@-IL3$+*0fSO8zqecz9HGTxoIgliJR2RPmg{31 znSFi4D2%KYdVMjBBO5mg^K1r`2Z!incyOP+q=*i9m~b2dvF{JY8AI8&(m{g-XDWV- z1ly5|8`_mENQGoYp1SGuV1ZIX^jjA&UjK6QlxQuhaY}uwecmP}fz&-1wG`yg*+d*N zyD&(#{zD~S|1<@@mhnWK`7vhA5g)VT6QpE zR(9`3%*<`0dFW5pZ8uelJYw0SoyX8qVP20)Wd&v+*-eiU zDovFQy}}V|5E30Gunryq3uS7U%Eh(n+D~0^yXkfoX*~M%Pq4r_CkTQrPWCjhltk1d zPJ3``pEo@=lv0NN^o5e=1MZQ08=DOqma~m+ zaw15+GQe!XDDqY3dlEjvqtHi!k2D(h=<{Nyoz&rDfAZUG19s`c~$gbLFtgaR$P z5USB4MdQ}VW2;L~?c39IK6kf8W@TyJx81J4YD&KiN`=;Vd@OEtrMUHFrl|IevIGD1 zS^uY`gc5s&Syq-sOfm@PIkWB8%O4Cz?!mIZLgMhN%NNciJt}5+E^*<)tn*6P-Gw;+ zvMHVRK7-Zq8)>g_K8H$7z;q&=3EV@nS*3>d9C?|qukzLE35C48uA}5K^fpX}n4f!j zJ6H-B-tc6ew05PAf!o=*YOk_=u5jAPz+8>#A)TwKm_9h00dC;1>EJ#V@Qo|HooLUL zNxqkPV|rXx5eL)@6~8Wy*}|PY+Sdl11n2>3mVoz z1ejHtmQE)W%~xO?eDS8i=jv+aNJ@3HH;i`c`ujVCO*fCY$FH2$!hZyEuXUTWxZVtC z;dnH}%j3RrWNi8N8rnpp*TB^Csh8l7ywJO?dIWJ9O*u2x2QPFDI4!Tel4Hj+wZR-R zAhjf*3%w+$Ok)nYVVf=UCR>hWgC z5+xiV(n&izYwCHf$~M@Or4KESaMq~q+oyLM)po(9NoH4hS4%Mn$v5}xhVSsg;QOfL zV|>8Pk?P{mR9$FZoQ{2~t?i}QC|v`tY{pIr90PYOaHSU4)}_2~Udf)794AbaQB-7U zNHM&}OWc|(_I>VZ^-xMp|91X1Z)f{^JnuFSk!>B2E?X69JJ0djU0g6?Eq*^;piSCE z^}VUOhZYWNVTM8q>hMebHOKJ#!<)~qJy!gp5O&wscjwl{V^u2Qh1{u@S)hy zLg)6lJI=!WtK&kJ8%EFyr-|8Jtgv9US9Ao8z$KbXRe&>7Db6}lG5StaTT`0jg*-8G zS32Z2mFIU??Z8|Et8wk<8<__?H0kd%$=e<|PBc@~E{HIVF?x`-cwX&u=S!p6+UHiH zcC(-k@L-fWINpy#e8BOg4eqydiP_K*55lrq?!es?_AEd)4XVbXOA+bNQ&3LRN`T%hQ8y-n%teA zAv0L#koVOqj#ek_`=FWlz&lPnjwy|hb#&OX1PN)vKmNskP#>Ac{l+Cz{R*l2G;8-TY>P`Ch|=F=|<@T%nypE!X*~ zjg*G6s)T{r;=z2IXG>R2;;ruFMiBv*N0=|8R0%?<{G1n{7e{|wFED^#^?G}|c&@N=zznyah!Lt6ub zjXUG~YU$;V%1$;xuXcmI-d*^F1-LfFE1xgEgwpMM-Q_f6_TfLjZOn`Y5wxhf0xU4m zfO!+$Af(Ocg8Wp z;<@5)3V4_3qaG#j7wzM{uzJ3=na9gsU6aJ^<`U-+)itL@n8V>MeOV_C)0NEP7-oM6e27U7SlI|Rzt`hWSl13&Wqo!oTMa}{M52Xyohhx7=JX= zjz+sxV}YX3iXCt-%0YG$ZgLH>-JeIuK79%n`(h^G{Nq=*n!;tyl#c_|j!FyJ(akvH z1B!Bt+Q{%APGa7AwN60Z@U~8aPuEm}+~)@;GEa#b_eBVI(&R=;3(3dIrX%6_o7GjJ zNz@(MG$K*~c%F_+4W$9-H}SToufc#**VaEkCF7 z>Vh&8ix(XXvJzeSrHi<}6TU}UWGG!GusZr92I#4nC?&IwGCz)*}VD zjSWPl;W)4>bcvyxOW$_&KfL7N_EYa_r@>9gF2I02jS7tQP@!{VWJdIo8b)RQiz0G? z&i6Z14t;Pdkgb3WlB~VR9olzw(7ZTmKkGwh7+VDMRA~j9uXp>$+@$l!XH2&d-}Hv+ z@?x{M`rf5KZlMy92pd|Oft1-m^$-N1Zka|+&d-kh@ro+VIzo3uwhe_Fp-1fHGyD6( z7(Z#IL|F?M9VT+_#IbT{pBu*cZcgvjxh*L#XEb+me?1opqFY6M;K@?Ht3aG9R!blF zgYaE$^j->SThN`ZY=a_V0;S81RKb}p?ag{aKRyo#eI==h%6P5Xlh;C;b zsPJb@8y2e3w|aZ-yN{7HnM$OLZGYBxcjLM3%Q<2<3SllycLgm+9SN)M`a|BNT&(6I zsrhOn)vuKM^-ccfykRd-0hOj}lnYe{{L2*L$^@nrg!$MjJ|sNfS=>3cI5nS2E-V9_ z1~sYUVn+^&r*tP}?QA(Gqgv)-0``g8uQSr1?VD~^6jbP zD4z~Du|Dq6hQ@^~vV>NyM!odtWn56XIF05*&QFXPSGn9V)Sb*8pHmR&SdEY&EN-vo z{*mlGv!fsgKLqV?U#}7LL>AsDR|Z-(Q{!WPMc^2>h3Og{NApPoMUir!E>Yy8*(;B4 zleNBqgt~Vk4x8fOlxTgoYdP>2S3})TzNXy0ztK*dCfO@7>vd(-sCoXYRY8NfxTd!f zzZLZ*a%gqEhVUW|)bC|-iR>g%HY%t)5pP!(?@juS7KuOWY8{+Unx^4$J%!S&&DAnx zdbP^ReuF$6y9cvk3F!0%oDq@D2)mK&O{jUp5p`L^FLt47C*Kl zvxEqmqSc5Q&b_96q3Ll-i>3}KWD&J|Io8I+7_JYr1-F~1M$78(%iDR_ z5Gw_@&fBdXja0fnM<(|ANif77yH9IjGMDipjbZIHv`$7xOLA_{yIpiziX`qLKWJ7A zOtHZ}bmW^bBMi9YWi=u?Ev`JMHV8#zxND<$1RF{}=UN}VO*WQ-Jf4* z`+O@UTDdGHjXb7#NoECXq~u(Y@4ks>ZYuW_MVeS$84;NH!kc7+FmaMm3zJ!hKVH!U zrObR6QwzGI(n7l`8@u2Kg}i8d;25nrT)2;q6qCDAz?N{enB(~} zZ^%)?g3z%0ZIlM6&GHpz*Gb$*BJyNp8)8cE5?1WG0hjPVp^NhKy{&!&v!H7)7qyh1 z=WWy1O1yFdSdYl)Eqs9B9w>yGZ{n98=rdZVD@`?U_b%0%)eUlrpkbYu%N^Cwwu`j3 zND_HF-kJbro5(Z=-1SOt<0qGZP7&Ok6fzOywL)h^^K5IXU{QUJ4eVkF5B(DVW}6Nx z8|MXi2GG+JMbykCqj}ytGU^))J|7;wE>RvOOkkD4%E8mPhv!HrTBvyXk$eVyySTR0 zG-+J&j;P-KQL0h3!CR7Gx>eGeY^-{V0P#H6ydc>!T$R7tVwt!vMcw0b=n)+-kKu7= zDn>X3RWAqFIkIQJV{f@~A%BVBB;!7?AY#CfBrgf;$Ka!?*IVi@#15!d3QSu?y-_ML z8)xD7Yq(}`II*8oFJUBOizqlIGS!M&wloP;Sb7s7+CH0E1szN6vfP`YFfL-cHy}go zx+T5Tpg`>v#oyKwtycBu^vVp%_?2wgR~+hCxxazdNA~7S(s(J-19uWX z6ly_VItyk$!YA4>Z=&kL4}$#_JQ>Etu9^jFgieOfF&P9WfAdCtCrohXLMf-C4x8g# zV@^*uYa^!KQ9YjUImc}g@#-kl8NyVGatMDt&h){yrlX|3q9WX`b38&Z4eA9p*D>FL z&fyQXy}}IGo>DO?oXEpFCBP7CgBxr)73(FDHMi1yYB6u1CTpKvSMHZ#&i1mV=-b2? zg$sSy%ST{PJmPIMlm4T~ofZWvP`v3m8L7m+Xf8{!^j?jEj3Y;j_HcE)2>cY#hoKO< zc|ufy2@0#W4W%A1L|+^3$LHxNzTXI$(^Y$i0YH?2(AS0Ri*v&jcN4gCzO}%cr%aB6 zT`w1l#nl8N(h5WxNkViCk@U0X?^9gV*Y&>NC^S+M)QKkv&?fc8c}Gq_hGeQk5T1)W zu&nVGBBRg~NJ)B>5=oi-?o-?a`Jx*Q?+Oi2?_c4^HLFl4*s-M6g+%0V&{`ONf?kpZ zUiEGu=hyS^d^u@$t{^ZjX6d%7`}~zc#0;{LGZC&lx>v~eXT{|RDRF$;@6xW_pepgk z0aPWY&Jsa7d!e~;f4&cJTWPaBViju#700oZ7^rl{K47FIlrc*cyRmh+3&QBgL=zBI zIE6620{6Z9j3{*t3%r~-`YKHWy&`efZNWIO$mQYiEN^Jpq>~+2xmMOwszk3XBJNG! zHCTVvX>u*oF>UEdM6|ONSl~V6kXX;#30v#f6w(%-G7&L{s6gZYEurF{k zL|eeKrk?E@HDG}YBdMUn0apbJiLIm=3LA|nW-KwnAHKxByj4+siSu>Bo0X7DFXVBr zK7tq!#~lP9&02fkJVvzEF4^$1=oYZbpX^jH-#Rd$!0fw{y_O%5ryV(mB z>_k>)tLrN6hPm<;QlVySgc@2C4VToZ9sTcjV%T>g;qj5+6Zc5->?w~+qOPbM6oS=w zJaxhIqfl)np@>L#eC8nX#OVGpNT_p{s~8Y+p7DUeFT50fUrSEw6yb4ufoXKLzrL@i z#s>>LEUzthaN!6v4UJf&Vr33Gy4g13blAXn<2kQ+n5DkD_r1t+&B!7KNH&X?RP7lK zvX~5(P#fQ9*kH9mrxoVsF5V2jX_w({Hgp4BE2eU>MZal$^d9RPKVSRD!hFG#bsH6x ziiVOHvx>@4)6l_1{>VsaCZ&`6@Qy&Rj%!pIzNh)t6MS|%EY`*cm(N5=^EADTUJEfC znMo@@zF2#5r+wyW+I5bBI7s2geCXJ87tA(5=gOrE>_g}%*{zRi0!O)?njrnPR2cm> z8$1Y*E11{&ITj~!*0E072Vdt-Zj-ka`wIw*(Cp>oM#e$m1tX z1T*W!XC>xdqHupH;cDb|zzrd#-18gb;+fvsw|QvrH4>7YSP=!|;PQh|`SXFb>d$$VU<{DiSb@hvK!qH=j_fs&>2p6oR^Zt?|P19uBlj$rjvOAg`NkxTOQ9vzxq#UCXJ9@&R2?h8%0tD*$vHX%)M zdLsdIN#paacRMNGRd;>xdg{#JL!d%9_!wzqi1^wxEG3G35HGpER}L1@#NU2%PB$iQ zX=St+%{|gE7r$qGOtuC&+~mZSpCt<_a0J1MX)B#w+T{T@Ejjn7Coi0QR1Bz|?6tal z3-Y8zTQ+{tU#<3HrM2C&SXonf3zGlxJ!lb!bD7DA!xQPT8H1_1?O29yl=wt7G`Ob= z$2zf|{Y(%(>v)wnPw#$q=}vEF#fe*1agWf)pwNwyaqZ*BDEmge`n)i_$cY&5;s{fC zj2OK1OYPl*m*45uTgJm`SdzKAa4wh@5-5f(T#_qGNc-{tA_LyTKIUjI8fuiHapc|IZ zV=d$R?ixtVdU6ES!AI-4n`SK2LxHrHpms^=KzH~7Y#FqMi}jtL@sq&<{htnO$8U^V z)iaGN(Zz;=2PYzY4xdp5-2n*&UIlz<@Fzl2?O)V*)KDGPbKQyB&pXyi<(q;zVG47C zZ{pDEF-Idxf_otmV%X=Xn_gDtEYR%igW~%fnwNsx3HT5)o@g0^t_30JT9_6zSO%ZD z77_V$_#%5F zDmUh}p5;Dl;TFf4yreThI5?7_asqXc+!L@mUlWG9MvdxGdcMzn_`-v4purW9d})=% zI7Bb@eRjt%(qR2rlv10v=rxcUqf$M#TnER{7RrLjO3X(r;MwmbYV1|dTHlAZ752Na z_{7$MO^ryDqL+qkHjLm-kyIs>?LpMg&9JI;D-PGyb(@38_O6{+GpPC}!qdZT!M1<As-oz{$OQBO!&d; z{4-M2bB|WQ^|x&Qug+rs_I>!@qiI$D1DbY*H>rVLseg9#`d>7)&~3)Hpow zwbbUwC2g())hnX}#XK3!-H)9gbxBIhEiQA!ziEcY`3RGfO+qtV_bGAO-Fd$|LN1^s z1|0IWDK2hY(_nkjyg9{sYe|9e{0~@ny&zf?sS|`YgJu7Se_T^et$=$gNsw!9a)&m+ zoMEI+O`1mU#%mS?Q{vpII$N~)d#c1P+?Z$gD7>T+VJnGBvxngltn(^mF2+68featq zYIKK1&mD`f*^llM?iFVLNFhrg{6fZnD)@4ugET|$SW`?ij6O@6Gn{_#f~coO!@E&p zCBd;^cNYHIvG@EBu>`uMxH0ymB_l!pw5X4E$!`FY$R3HpyIpY%g=45MXBHD{zd__`{zFmr}6wGyT^lc?~zPuOlkdiM* zrmuK)kfKdSB50KpRQ%7-I7nEd^FZs|0BiHr&ZvINaZ$eSZ=*k=p>#rH91@CyjhfTQe^5P*>^{Y!(*c$AS->m;z&cWntQnpG6;dV7Ue0+eA>WI^s!) z>bdB7%*!o%c@^V!8Y^4#2AAn&)#R)X0ik5O>+zQ$VA-8_&ayN-AXbX5#-9a0F4`e@ zms`Mh*+YhBXxCr{x7Ib@cS1g$CnAtIzkNLQ{MQ7+Hnew`UC4>fh^8t&n5bc&`5CY`qKrf>Lbl> zVfxR}r~P(^0eS~qKYMH7HhOZnUmmh8I|(OuQI)@51-}i0-jZ9t%F6S4mi(1T)Opc1 zdv6eXJ|EYXOg=83X58(;=uK}}P)MQkoG*Y&N#x)Nq>ymp#s)WOm$(c2HXSGUxM+9s zrpH_%eCZuvu!2W^zBj|g7|qoi=!rMX1Sfeg!nt5O&dV-4S?Alff|jrI5C=uL^JX(V zC`ocKRf;2V)}Np7gEPO4vn*XE5>q)8L5tpiV@fM zR0(^GNu;Py&CLy$1Wz@z2B^oozAM)om"-0QgQ_f&;P+@ae|xCKI-OpCg4A{V9= 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

txr3cvg?DddS~a=5*D+7If^1vV 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%0Ahv6zr6ARw*_`jR9g7o+ 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

gKrND=tx1)lqF~lNhyCK#r{*<~^zl|> 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 Xw=kVf=>HmO>>rBppYw?K*W&*G6`{5$ diff --git a/doc/testbenches_doc_resources/legacy1.jpg b/doc/testbenches_doc_resources/legacy1.jpg deleted file mode 100755 index c3579df3e4a56521eff8f23df1dbca9ba9fd3a59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107882 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 Q=k@ozuRl0u|MlB{0A&rZtN;K2 diff --git a/doc/testbenches_doc_resources/next_ci.jpg b/doc/testbenches_doc_resources/next_ci.jpg deleted file mode 100755 index 2d4111510c061b5d18ed1ae3097e3c6cc0040437..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157592 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�A(SmYoqJhO6gzHn~W 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 CdZAGO diff --git a/doc/testbenches_doc_resources/next_dev.jpg b/doc/testbenches_doc_resources/next_dev.jpg deleted file mode 100755 index 72e9f63bf91cdb7fd47a44780126b7269bf0475f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185772 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 diff --git a/doc/testbenches_doc_resources/outdoor_live.jpg b/doc/testbenches_doc_resources/outdoor_live.jpg deleted file mode 100755 index eba44a3c00e7456c7d2d0cc12ea1e77db31ae10a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167702 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 Date: Fri, 6 May 2022 12:17:18 +0200 Subject: [PATCH 196/226] calling config_csiim also in sa --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 34 ++--------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 8e8959c597..e22bca592f 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1412,39 +1412,9 @@ void fill_initial_SpCellConfig(int uid, NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1,sizeof(*csi_MeasConfig)); SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup = csi_MeasConfig; int pdsch_AntennaPorts = configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; - if (pdsch_AntennaPorts > 1) { - csi_MeasConfig->csi_IM_ResourceToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_IM_ResourceToAddModList)); - NR_CSI_IM_Resource_t *imres0 = calloc(1,sizeof(*imres0)); - imres0->csi_IM_ResourceId = 0; - imres0->csi_IM_ResourceElementPattern = calloc(1,sizeof(*imres0->csi_IM_ResourceElementPattern)); - imres0->csi_IM_ResourceElementPattern->present = NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1; - imres0->csi_IM_ResourceElementPattern->choice.pattern1 = calloc(1,sizeof(*imres0->csi_IM_ResourceElementPattern->choice.pattern1)); - imres0->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 = NR_CSI_IM_Resource__csi_IM_ResourceElementPattern__pattern1__subcarrierLocation_p1_s4; - imres0->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1 = 6; - imres0->freqBand = calloc(1,sizeof(*imres0->freqBand)); - imres0->freqBand->startingRB = 0; - imres0->freqBand->nrofRBs = 108; - imres0->periodicityAndOffset = calloc(1,sizeof(*imres0->periodicityAndOffset)); - imres0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; - imres0->periodicityAndOffset->choice.slots320 = 0; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_IM_ResourceToAddModList->list,imres0); - csi_MeasConfig->csi_IM_ResourceSetToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_IM_ResourceSetToAddModList)); - NR_CSI_IM_ResourceSet_t *imset0 = calloc(1,sizeof(*imset0)); - imset0->csi_IM_ResourceSetId = 0; - NR_CSI_IM_ResourceId_t *res0 = calloc(1,sizeof(*res0)); - *res0 = 0; - ASN_SEQUENCE_ADD(&imset0->csi_IM_Resources,res0); - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_IM_ResourceSetToAddModList->list,imset0); - } - else { - csi_MeasConfig->csi_IM_ResourceToAddModList = NULL; - csi_MeasConfig->csi_IM_ResourceSetToAddModList = NULL; - } - csi_MeasConfig->csi_IM_ResourceToReleaseList = NULL; - csi_MeasConfig->csi_IM_ResourceSetToReleaseList = NULL; - - config_csirs(scc, csi_MeasConfig, uid, pdsch_AntennaPorts,curr_bwp,configuration->do_CSIRS); + config_csirs(scc, csi_MeasConfig, uid, pdsch_AntennaPorts, curr_bwp, configuration->do_CSIRS); + config_csiim(configuration->do_CSIRS, pdsch_AntennaPorts, curr_bwp, csi_MeasConfig); csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; From 02d49ed3b63de016a5b53ed572cf31a2617042ff Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 6 May 2022 11:56:11 +0100 Subject: [PATCH 197/226] Fixes after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 10 +++++----- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 ++++---- openair2/RRC/NR/rrc_gNB_reconfig.c | 1 + 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index caecc6be43..9c3e142e0a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1183,7 +1183,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_SearchSpace_t *ss = (bwp||bwpd) ? sched_ctrl->search_space : gNB_mac->sched_ctrlCommon->search_space; - const int bwpid = bwp ? bwp->bwp_Id : 0; + const int bwp_id = bwp ? bwp->bwp_Id : 0; const int coresetid = (bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : gNB_mac->sched_ctrlCommon->coreset->controlResourceSetId; /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ @@ -1197,7 +1197,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %d, bwp %d, cs %d\n",UE_id,bwpid,coresetid); + LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %d, bwp %d, cs %d\n",UE_id,bwp_id,coresetid); NR_ControlResourceSet_t *coreset = (bwp||bwpd)? sched_ctrl->coreset:gNB_mac->sched_ctrlCommon->coreset; nr_configure_pdcch(pdcch_pdu, coreset, genericParameters, &sched_ctrl->sched_pdcch); gNB_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu; @@ -1362,7 +1362,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_format, rnti_type, pdsch_pdu->BWPSize, - bwp? bwp->bwp_Id : 0, + bwp ? bwp->bwp_Id : 0, gNB_mac->cset0_bwp_size); LOG_D(NR_MAC, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index dc98b84750..2897a86c31 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -875,7 +875,8 @@ int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, int Mod_idP, int UE_i int nb_tci_states = CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList->list.count; NR_TCI_State_t *tci =NULL; NR_TCI_StateId_t *tci_id = NULL; - int bwp_id = 1; //TODO + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; NR_BWP_Downlink_t *bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; NR_ControlResourceSet_t *coreset = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]; int i; @@ -1249,7 +1250,7 @@ void evaluate_cqi_report(uint8_t *payload, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_2tb = temp_cqi; LOG_D(MAC,"Wide-band CQI for the second TB %d\n", temp_cqi); } - sched_ctrl->set_mcs = TRUE; + sched_ctrl->set_mcs = true; } @@ -1711,11 +1712,10 @@ int nr_acknack_scheduling(int mod_id, NR_SearchSpace__searchSpaceType_PR ss_type = (is_common==0 && (sched_ctrl->active_bwp || ubwpd)) ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; uint8_t pdsch_to_harq_feedback[8]; - int bwp_Id = 0; - if (sched_ctrl->active_ubwp) bwp_Id = sched_ctrl->active_ubwp->bwp_Id; + const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; int max_fb_time = 0; - get_pdsch_to_harq_feedback(mod_id, UE_id, bwp_Id, ss_type, &max_fb_time, pdsch_to_harq_feedback); + get_pdsch_to_harq_feedback(mod_id, UE_id, bwp_id, ss_type, &max_fb_time, pdsch_to_harq_feedback); LOG_D(NR_MAC, "In %s: 1b. DL %4d.%2d, UL_ACK %4d.%2d, DAI_C %d\n", __FUNCTION__, frame,slot,pucch->frame,pucch->ul_slot,pucch->dai_c); /* there is a HARQ. Check whether we can use it for this ACKNACK */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7331cae4f0..ff6ae976b1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1476,7 +1476,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t if (tda < 0) return false; int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, tda, mu); - const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) % 1024; + const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) @@ -1871,7 +1871,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, * create it */ - const int bwpid = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; + const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; NR_SearchSpace_t *ss = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->search_space: RC.nrmac[module_id]->sched_ctrlCommon->search_space; NR_ControlResourceSet_t *coreset = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->coreset: RC.nrmac[module_id]->sched_ctrlCommon->coreset; const int coresetid = coreset->controlResourceSetId; @@ -1927,7 +1927,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->time_domain_allocation, UE_info->UE_sched_ctrl[UE_id].tpc0, n_ubwp, - bwpid); + bwp_id); fill_dci_pdu_rel15(scc, cg, dci_pdu, @@ -1935,7 +1935,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->dci_format, rnti_types[0], pusch_pdu->bwp_size, - bwpid, + bwp_id, nr_mac->cset0_bwp_size); memset(sched_pusch, 0, sizeof(*sched_pusch)); diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 0c03ec76a1..cc23810f60 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -310,6 +310,7 @@ void fill_default_nsa_downlinkBWP(NR_BWP_Downlink_t *bwp, bwp->bwp_Dedicated->pdsch_Config->choice.setup->rbg_Size=NR_PDSCH_Config__rbg_Size_config1; set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing, configuration->force_256qam_off ? NULL : uecap, + secondaryCellGroup->spCellConfig, bwp->bwp_Dedicated, servingcellconfigcommon); bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI)); From 04db6ef536d9c89c66b738be19c3bb4a357a5da0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 May 2022 12:21:05 +0200 Subject: [PATCH 198/226] Update CI bench images --- doc/TESTBenches.md | 76 ++---------------- .../4g-faraday-bench.pdf | Bin 0 -> 53134 bytes .../4g-faraday-bench.png | Bin 0 -> 92391 bytes .../4g-faraday-bench.tex | 59 ++++++++++++++ .../5g-nsa-faraday-bench.pdf | Bin 0 -> 337513 bytes .../5g-nsa-faraday-bench.png | Bin 0 -> 89436 bytes .../5g-nsa-faraday-bench.tex | 55 +++++++++++++ .../5g-ota-bench.pdf | Bin 0 -> 232494 bytes .../5g-ota-bench.png | Bin 0 -> 90027 bytes .../5g-ota-bench.tex | 63 +++++++++++++++ doc/testbenches_doc_resources/antenna.pdf | Bin 0 -> 4886 bytes doc/testbenches_doc_resources/b200-mini.png | Bin 0 -> 238906 bytes doc/testbenches_doc_resources/b210.jpg | Bin 0 -> 32877 bytes doc/testbenches_doc_resources/n310.png | Bin 0 -> 120716 bytes doc/testbenches_doc_resources/phone.pdf | Bin 0 -> 4358 bytes doc/testbenches_doc_resources/quectel.png | Bin 0 -> 88455 bytes doc/testbenches_doc_resources/server.pdf | Bin 0 -> 4366 bytes doc/testbenches_doc_resources/x310.jpg | Bin 0 -> 11188 bytes 18 files changed, 185 insertions(+), 68 deletions(-) create mode 100644 doc/testbenches_doc_resources/4g-faraday-bench.pdf create mode 100644 doc/testbenches_doc_resources/4g-faraday-bench.png create mode 100644 doc/testbenches_doc_resources/4g-faraday-bench.tex create mode 100644 doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf create mode 100644 doc/testbenches_doc_resources/5g-nsa-faraday-bench.png create mode 100644 doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex create mode 100644 doc/testbenches_doc_resources/5g-ota-bench.pdf create mode 100644 doc/testbenches_doc_resources/5g-ota-bench.png create mode 100644 doc/testbenches_doc_resources/5g-ota-bench.tex create mode 100644 doc/testbenches_doc_resources/antenna.pdf create mode 100644 doc/testbenches_doc_resources/b200-mini.png create mode 100644 doc/testbenches_doc_resources/b210.jpg create mode 100644 doc/testbenches_doc_resources/n310.png create mode 100644 doc/testbenches_doc_resources/phone.pdf create mode 100644 doc/testbenches_doc_resources/quectel.png create mode 100644 doc/testbenches_doc_resources/server.pdf create mode 100644 doc/testbenches_doc_resources/x310.jpg diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index fc05299110..547fd5a23b 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -45,29 +45,9 @@ Note: The available resources, and their current usage, is indicated here: Note: obelix and porcepix are both used in the OTA testbench and the 5G NSA/Faraday Cage testbench! -``` - asterix - ┌─────┐ ┌────┐ - │ ├────────┤N300│ - │ │ └────┘ - └─┬───┘ -porcepix │ -┌─────┐ │ nrmodule2 -│ ├───────────┘ ┌───────┐ ┌─────┐ -│ │ │Quectel├─────────┤ │ -└──┬─┬┘ obelix ┌────┐ └───────┘ │ │ - │ │ ┌─────┐ │N300│ └─────┘ - │ └──────────┤ ├────────┴────┘ - │ │ │ - │ └─────┴────────┬────┐ - │ │X300│ - │ └────┘ - │ UEsimbox - │ ┌─────┐ - └────────────┤ │ ┌────┐ - │ ├────────┤SDR │ - └─────┘ └────┘ -``` +![5G OTA Testbench](testbenches_doc_resources/5g-ota-bench.png) + +[PDF version](testbenches_doc_resources/5g-ota-bench.pdf) | [LaTeX/TikZ version](testbenches_doc_resources/5g-ota-bench.tex) if you want to modify to reflect your setup ### 5G NSA/Faraday Cage Testbench @@ -76,58 +56,18 @@ porcepix │ Note: obelix and porcepix are both used in the OTA testbench and the 5G NSA/Faraday Cage testbench! -[Proper image to be followed up] +![5G NSA/Faraday Cage Testbench](testbenches_doc_resources/5g-nsa-faraday-bench.png) -``` - obelix - ┌─────┐ - │ ├─────B7────────────────────┐ - │ │ Faraday Cage │ - └┬────┘ ┌──────────────┼───┐ - │ │ │ │ - │ │ Y │ -porcepix │ │ │ -┌─────┐ │ │ │ idefix -│ ├──────┘ │ Y──┼────┐ ┌─────┐ -│ │ │ Y--│----├───────┐ │ │ -└────┬┘ │ Y──┼────┤Quectel├──────┤ │ - │ │ Y--│----└───────┘ └─────┘ - │ │ Y │ - │ nepes │ │ │ - │ ┌─────┐ └────────────┼─────┘ - │ │ │ │ - └──────┤ ├─────B78─────────────────┘ - └─────┘ -``` +[PDF version](testbenches_doc_resources/5g-nsa-faraday-bench.pdf) | [LaTeX/TikZ version](testbenches_doc_resources/5g-nsa-faraday-bench.tex) if you want to modify to reflect your setup ### 4G Testbench(es) **Purpose**: 4G/LTE testbenches -[Proper image to be followed up] -``` - hutch - ┌─────┐ - │ ├─────B7────────────────────┐ - ┌──────┤ │ Faraday Cage │ - │ └─────┘ ┌──────────────┼───┐ - │ │ │ │ - │ │ Y │ -nano │ │ │ -┌────┴┐ USB ┌──┼─UE │ carabe -│ ├─────────────────────┤ │ │ ┌─────┐ -│ │ └──┼─UE │ │ │ -└───┬─┘ │ Y──┼───────B7UE──┤ │ - │ │ │ └─────┘ - │ │ Y │ - │ starsky │ │ │ - │ ┌─────┐ └────────────┼─────┘ - └───────┤ │ │ - │ ├──┬───────B40────────────┘ - └─────┘ │ - Y (sniffer) -``` +![4G Faraday Cage Testbench](testbenches_doc_resources/4g-faraday-bench.png) + +[PDF version](testbenches_doc_resources/4g-faraday-bench.pdf) | [LaTeX/TikZ version](testbenches_doc_resources/4g-faraday-bench.tex) if you want to modify to reflect your setup ## Pipelines diff --git a/doc/testbenches_doc_resources/4g-faraday-bench.pdf b/doc/testbenches_doc_resources/4g-faraday-bench.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e31789e9acb9a3cc05719d98304966708925ff9 GIT binary patch literal 53134 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 ZI_Wz&xj6uFW@Q3yKEsldipq<@{x9A38&d!P literal 0 HcmV?d00001 diff --git a/doc/testbenches_doc_resources/4g-faraday-bench.png b/doc/testbenches_doc_resources/4g-faraday-bench.png new file mode 100644 index 0000000000000000000000000000000000000000..c69065a369c3f94b3e8a856b892f6b3bed2b42df GIT binary patch literal 92391 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

h0&06N?X9REx=xt1C&ZPLaVB>*KpD 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 literal 0 HcmV?d00001 diff --git a/doc/testbenches_doc_resources/4g-faraday-bench.tex b/doc/testbenches_doc_resources/4g-faraday-bench.tex new file mode 100644 index 0000000000..6071c89947 --- /dev/null +++ b/doc/testbenches_doc_resources/4g-faraday-bench.tex @@ -0,0 +1,59 @@ +\documentclass{standalone} + +\usepackage{tikz} +\usetikzlibrary{backgrounds, positioning, shapes.symbols} +\usepackage{helvet} +\renewcommand*{\rmdefault}{\sfdefault} + +\begin{document} +\begin{tikzpicture} + [ + font=\footnotesize, + faraday/.style={minimum size=3cm, draw, dashed}, + duplexer/.style={draw,fill=white}, + ] + + \node[faraday, label={[anchor=south west]above left:Faraday cage}] (faraday) {}; + + \node[above left=0cm and 2.8cm of faraday, label=above:hutch] (hutch) + {\includegraphics[width=1.2cm]{server}}; + \node[right=0.3cm of hutch, label=above:B210] (b210h) + {\includegraphics[width=1.2cm]{b210}} edge (hutch); + \node[below left=0.35cm of faraday.north east] (anto) + {\includegraphics[width=0.3cm]{antenna}}; + \draw (b210h) -| node [pos=0.25, duplexer] {B7} (anto); + + \node[below left=0cm and 2.8cm of faraday, label=above:starsky] (starsky) + {\includegraphics[width=1.2cm]{server}}; + \node[right=0.3cm of starsky, label=above:B210] (b210s) + {\includegraphics[width=1.2cm]{b210}} edge (starsky); + \draw (hutch) -- (b210h); + \node[above left=0.35cm of faraday.south east] (antn) + {\includegraphics[width=0.3cm]{antenna}}; + \draw (b210s) -| node [pos=0.35, duplexer] {B40} (antn); + \node[below right=-0.2cm and 0.8cm of b210s] (antn2) + {\includegraphics[width=0.3cm]{antenna}}; + \draw (b210s) -| (antn2); + + \node[left=5cm of faraday, label=above:nano] (nano) + {\includegraphics[width=1.2cm]{server}}; + \draw (hutch) -- (nano); + \draw (starsky) -- (nano); + \node[above right=0.0cm and 0.35cm of faraday.west] (phone1) + {\includegraphics[height=0.5cm]{phone}}; + \node[below right=0.0cm and 0.35cm of faraday.west] (phone2) + {\includegraphics[height=0.5cm]{phone}}; + \draw (nano) -- node[above] {USB/adb} +(5cm,0) |- (phone1); + \draw (nano) -- +(5cm,0) |- (phone2); + + \node[right=1.5cm of faraday, label=above:B210] (b210c) + {\includegraphics[width=1.2cm]{b210}}; + \node[left=.5cm of faraday.east] (antc) + {\includegraphics[width=0.3cm]{antenna}}; + \draw (b210c) -- node [pos=0.35, duplexer] {B7UE} (antc); + \node[right=0.7cm of b210c, label=above:carabe] (carabe) + {\includegraphics[width=1.2cm]{server}} + edge (b210c); + +\end{tikzpicture} +\end{document} diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f6d960c1a257651b538b404f8f019438d3014f15 GIT binary patch literal 337513 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�P#Ab?f8M>rnq?n9rvn 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�EUbc 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ξ9jO zt*)$cC8Bc+`Vj_Z~gC_we35RBGGsg(a@d04@-^ z@;R;3frJ=6vB5t7!GuJf#JxWCZfZUekp}uA<*H4Wccmdw+rQ&8+S92_Ere%5JDChd*`pb z{Y8fV_)7dgYpram=)AvAelO2A1y_D~_qNd<2a6kGr+o6s&qqeaYib%1h7$-RJgybp zgm0+B)YhTP%d0CYfVgc$Lrx2HKrL148qugGfk4D$umHvg#1>*R01wt`GA9x#G?i4} zf~#-AqnV^;2@@-#36tIn7p_^=+|}{!=byRq*~g!bEG^aW+Z)7`Qcg>)h)!_oR&HGB z5D88%pPHSVJ~@A)Yjt5K4c!s-*t3yZ3Za(X(%q92C}d)lED#KY!V!Nm#xSa;r>2{k zS`Ln_ix1D z8qioYx*7Zkc)h@)8gVF0^Y(`y-LDh>ZNmCM*4^aPJ}?q(qO{<}T%eyZ1}TP4uB@r) z9_$Il!~R$R%_kG3oMWXW$BK)Om6jeWD=V$8u57G3SbXg9{ZC-ToH{X!pyc5+VvJUd zHAwNs4yvJ}Nh78OoXt+HIUAciF&gyB9S((B*FoSiuuKY7$_u9>MzjQis;t58h zzNs0P>CSqi@qAzG&NsJtbqBA^XD(e^3B_z{YoD$C5e|n>cE?g_cvz>i!)^&C6LO#3 zo^Uv`L0izsHfiRT=HaHb&{ifqA`|LK2qno=vFeE~wZ+)FGC>W)k3bO=r^<^Ma0^_y@75tU4&1I5jvB7l=|exxW%niG{UgKR$mDw=fI|U7`?JqI z50Ln~-+ue^k3RYC4}TQtHQ-a=x-vI3C^bVJ8snW=sKWpZ@WLnxt=&RAIZg4IJG>6m z`B{ct2N-Vfc{+y%*d|@q`4z2%bL8L?MJ30N7auDwEh#N6+4K0$;nRy$qe|+uPR>mM z9S+rIy4{_9x#5XXK=mtEp0osgP0hqmEW25W-?;-sAi|+P!Cffdf9Dp5%?t#BerU2! z5HLIvi2xmrBn*KRFI4&fhHvbARVcSFUu1W*hXxjwGeQ>^HyKDE}J$v>)vG2gagGYYy@Rr?s z_Bbr+Slka~s;vgI$Hh|1^bX5|fA_a+KD8BBcjWQE&vd3gzWv^tJ-RpY_7C2=rBF#u zES*?BwHnF9RW^eo;Ltcs?J^!kE}$Y(TqOeZ1}ES>2RfV%!<+?lI5;#?Kyr@0gRAX; zFs?^nE(ZVyQXC?=Q6(^H1!ld-0_kw6K?`UQ%ck7npnfQ_l5_pHzjrYQ{EgD5GTQ-*mYZKIR z7DW+*s!s_&Nk=soMDL+bS^{`KxFn)N0vu#$JJF9d2h&FD+U6J4FbL>#Oy z257FRS?RQCZ8lFJ2!rxZ?qERgwCU_N@XPiL4$93&i{E?s@})Q4d>x)u2hTr3O79(3 zad!$c-!D+fMT4E##X)e<Iu7hV6i}1lYpwkV(|cjXf&>}styS9va+h;(hBIlxV)&Sth}NY zg=#7;21|Vzxby`lB_(C0rRAliWjGw6yu1oB?iG&2Yj%-)f=J%jAqPiLsi9|CP46SVxaGAhjaak-5hr@&DifP_^;E=hu z^Pq~oN6XtMqy+Na)eQ~(y}9mOXBCSG#4w6SYT{9<8N^gNnag*|)oKi`DFUtxGu_n+ z_9I(%5KM|~+jlmAw}(P$Xu#CeHZtf;kw7RA2m!jmVu!)tQ5ZbX7ms3->>;%QJz}H5wP2&EQ49!PHT=t0)P7Ii}&-U zR|b98o;=TFQoyC_&6_v%9@FUf(9+VJ$?s?vbEtA55aDE{kfIdPlp=~!2q|!&!xbWc zak^Ft0M3E>83HLT<7(vq<2=0*>M;&0bAWN4Q4O2qY5;J6aj{Vc{vm?VkS`VtWzwOA z?xaQa;Q#u-m6>p(O+~U9|M=<6zyF&DcKttpbLLzQz(Huzd*jh$cef)H^v7ddp-3WC zO697yHp=$LcX4f6naLov82iRXdItxb0e`A9+u5DX2kc!zi`(On>h&E)14}L&pP%9C zv?7CEpwm5dVIB$=es_EA``g1K`Js`)bE}I?xmfD7Me{wczkHt8RPx~e_Q32wgl|=L z_2*sjhyqS)tJaNiNJ|?XHsSOzx;Lh=8W}S~B?|*Ihe2*Ns$6!J2hM>wY&y7O2@)?s z3NZC|hfwH{yrK`88R6Cz817vUnXBM5i_Q-OpC4eQLVS@3 zP;q);x@{oUIFfB2>tT7Uo=6y6vw%e*-UT%zgoaAP`?&GDLU0vd_*?{3*uNT}S3m)ri;Iq8s*dm4{_y3jL@uv)Iys?mN8eCBoQ_2@kx{~R_NKo0p3-AHiHNU}K?5KJ zRDf~7@Oo}rPj8RPX#)SFr$$FQ?50>cskIvuv1p5cwK_S5mGaR{I(REY0uhNsrPG+; z`_pI)8jVGw(7}0CRedX|O`Hh)U%9}4$-3)=Q~+%(s}=4BM!^ZFI02s@yDho^djQ4scqcJkpWGu>NtD)-291IGM_d!Gp@GlnSkChKBT~90uoT; zDySqA@EkJ3;r&g3bS5$@Sta2Bl51qh!3XkNuYk_=a!7|mW;k>&02ntwrb_?B$kNh$ zI37*sx(Pw&g_|o^ugw@nVyzk}#bI9i^7-30PyPC(rOA^c{&-ZV*MiG-0K?(o!FV*{ z^?8;TmsS?$OnO~QYrEcR>9AX+W@D-g3Pu{;&ViBPuRr_bv(>&27JGj2(Fb%o30#f8 z{L`O$qv3c@XW!5u_@URXoPZd9=ff{Px~{RATyAG38aj%qrG*@}T<1$Ktu7Ab2nYV@ zo6mnLvgvX|gD20P$qx)d+kz}P2#bO z>_(B@B(|I6PHTq~DousU;mul$+1{C~o9nyr?DN-Oe;L)E>P%D zKYtpVPXrQCxycag?hL0=gX801b%WLvIDZ0VUBHRms`R@s=jU1j7P(%<>rFSD8ZYSy zq3jyANvEG19(d}kH{aPaJ2G~1Zsx{iS!axIHFSU_%nr3-fy^AFaiZU2@<1g#8k@}( z4L@`B3Sj9|S1w;XclNobFTZ&GskdHx>BBc)`_-49e)qfIu6_R(pefU_(kt4;`@YKj-MP7))+swwQ{KRCuVb{7Q}DH1%8?_- zOG?TsD{Fv;ud1p6$4?%9*z9qRj1Essj|ZcXHif{HiPdR@Ot+O_RJ6Mc^+tJpGXXH1 z&E^7}GMO9-gj2{ufn6Xxcx^3Ya%;eZc4{Z4M(9CHE@_*OTI4!8Q!i`akf%>?oZW-p6br5Zc;XNnn`+7cW5eqoF+l za1e@0%K032Wz2d+L;+8%lQZjC?X|47Mov2vAQaLt0!kgbb!v9u>rX!E4LRPpxSVoZ zfWilB;-SMwj~ppFeE9h8J^TOdCl5WbfB$i8163=dXgh4(srE~V>`t$TA`{O| zPE#bj*@XqNl-I_GrdL$7pqkodfc5NgSrqVRIzok?Ef0r)I9*JT-e^ z+z|FV1A*03CtrN=rpf1p7!FHiBs6FMRE&jc&d)U^y>JDqT@vvLQbB$;%Il2sb8${j zoS9272eXW!F4{;Bc{~Tya_eLsXldg75Mf~myEuYb9L6n;Hm-~}tb${z>C{C1@<{FS zXwC9y!}3_ei6Pu6&?Q5Coz4OhtLzmCiCf(;wpM!eNgzYWkJ!^lwlYjDT z{ZNJzbaDd@Uw==0a@3HF^358R&4P46yc=0`D6J-WJcv0vgNZpay*;tv{P5*7ombC< z#`>)3D9>TxI4vBvo#HjK9R`8j3=M#Qx^F>Ew7?aF$p>{oS?}MnK0?}!Y$(VqMsQiA zaac7DyV`2j*sMCcO=&jjttM9@v~>OANMBZ^QhDGTV0b}_BX$bH@PZCUyp-A5*+S1N zq~R4}q#$N^AsG&I_(mh8&?+3+%Dh*E7b1o0ZqI*CivQ2W_@7N4{@FbFpN08GOHb(^tZUEV1G{(cIdJ&MuH8U@?|)+7zJGr3A#XI~ z3HxO#6@^Y^O2smn)L^&k%@%=L9`Oc9K65P!hr<%U^#YkpYiR+O5|9%PmLU`hvhj}` zEvAY1M{J7NaL?#)zo$P-QnQ3gRz8<$5p&@B8VKX{tTuzkdGXSDv)5$}xD+Ne)vTi0 zb#)R3UMs3n^2+4gMw6nxssV+piaGXZ-4XSS?VCi6RzSNX7E0Wv!_9KKSTo7f(6)gtsp)QE});ckVt`R08OI=BF1U!)nNpT4rGL*6a zz_ozk&^%25bN+g~P{{#m91f)bj0@p>xBy_>4BbP;J{D-4JzWLlx(Xa(ivbW`Y}6_2 zCR4~~0IcwPfdmCi0IxaK)#;5#^0}NZ6oPiRPRyKJU3}xEmuMoP+F=u0jPQ*39=S>X z!V52U@G0H;_6avvuNEj2!fYxD{+oNk!7~@mUw{5twbiip+x3oxH!hC)<8enQVD`eo z(&vr$b_*;fzSG8Y*?10XD&N~-HqI|EW_o(y(U!<~H5W1#6Y{s64t2oOygFICG>lFA z=}A8;?qT?CbhlaHvGTm&-Xe0E~xd9X6xFY66!+VTS2harAClq#w)&JsIITBtgCB4my}h34B;pd6jHjJhvl@NII+l;OGzq88#AJ-q+FH;8b_p2UeWhiiL#69h>Sl%DZHBO$p_7;EI&l;tS-`GflWI9s9FttjCfBhk zg_Qb34dwM6txN`!D-++odIQ&j&#YXOYE&M7AQtbbK=>7<)pdAyzaX`c@r?v<*8{hS z+B#Ub0r$S`+jf~EfulO{F^w=!&EK!)TP&Rp11r%TBnp^y&( zkMEqREH2)bTT`px0-o#C*+Z}9 zLesdGZ_)yWi_AKKK_djXGiby{IDJ53G5`pS&rGF9hJ`?x+l`W-CpA1Yd~*I0kYdj~ z-K_3pyR7nnYiwq6bau*{=$=_w5jZVX?2d!9dR$vWMQ!=y^yFY>(C+oj%+F>$p<)Zic-Hwj&QR*T=Ob~ywQpCoE)a;Ujh!_ds6D;yde9s)PC9%$5RcX3EXH8aWLAL>Y~N{tx+$d+fR%67~NiW(9L#Q z7&_HkZ@%JKTkPzO-oE+7pMLWj>Ogm$Q~%tJCze;1`AVr!)yb1fe37oFuifTKgy7b| zo9G96o~2i)(Ii`N)4}#PWhO(XPBVLY$+xx;J#*5W2x}sK-t55W_}I^W{OOBN-5H*l zfkTMUshuXb%YY_a!N7C$_Il~k`Bz`Md-}|(+2euUNG!Av-M5A9PUuE}3Ki$*j8Qv3 z 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

    SvCyo3%tBgZ@e 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�co^0J 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�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%0D%sqj=-Kn=?=3kz@z+nwCt^ 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

    vh4ehB$&?ymC@{5J~(+oo1-;TWB{07$j*UR>Bk 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 S(m*YAP~e%1va*GvCFDN?3v0Ll literal 0 HcmV?d00001 diff --git a/doc/testbenches_doc_resources/b200-mini.png b/doc/testbenches_doc_resources/b200-mini.png new file mode 100644 index 0000000000000000000000000000000000000000..0355e45f1837b3ca5129566cb524af070ee06c5d GIT binary patch literal 238906 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

    xQ>J8$D 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 I7*TxYiu>Ovu{7nDFn^eYsIAR?lLgvc=Jp6l%D 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 O0000S`{PTd|i30zD+sTMw!)aQ? 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 db@{|^9|4aNWf literal 0 HcmV?d00001 From 5031649c4766364eba2995e1d12331cc4c19b9e6 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 6 May 2022 15:57:58 +0100 Subject: [PATCH 199/226] Improvements on BWP switch procedures and harmonize it with RRC processing timer --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 66 ++++--------------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 19 ++---- openair2/RRC/NR/L2_nr_interface.c | 5 +- openair2/RRC/NR/nr_rrc_proto.h | 6 +- openair2/RRC/NR/rrc_gNB.c | 13 ++-- 5 files changed, 32 insertions(+), 77 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5fbfad04d2..0d5755dd71 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2365,9 +2365,8 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG scc, genericParameters, NULL); - sched_ctrl->bwp_switch_info.current_bwp = bwp_id; - sched_ctrl->bwp_switch_info.next_bwp = -1; - sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_INACTIVE; + sched_ctrl->next_dl_bwp_id = -1; + sched_ctrl->next_ul_bwp_id = -1; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; if (ubwpList) AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", @@ -2900,52 +2899,6 @@ void nr_mac_update_timers(module_id_t module_id, } } -void nr_bwp_switch(module_id_t module_id, - frame_t frame, - sub_frame_t slot, - int UE_id, - int bwp_id) { - - NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - - switch(sched_ctrl->bwp_switch_info.bwp_switch_state) { - - case BWP_SWITCH_TO_START: - LOG_W(NR_MAC,"(%d.%d) [UE_id %d] Schedule BWP switch from bwp_id %ld to %d\n", - frame, slot, UE_id, UE_info->UE_sched_ctrl[UE_id].active_bwp->bwp_Id, bwp_id); - sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_RUNNING; - sched_ctrl->bwp_switch_info.bwp_switch_slot = slot; - nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE_info->rnti[UE_id], bwp_id); - break; - - case BWP_SWITCH_RUNNING: - // The BWP switching takes at least 10+6 ms (3GPP TS 38.331 Section 12) - // gNB needs time to schedule and send RRCReconfiguration message - // Therefore, we wait for the same slot in next frame (10 ms) before update bwp_id in the gNB - if (sched_ctrl->bwp_switch_info.bwp_switch_slot == slot) { - const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; - const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; - const int bwp_id = servingCellConfig && servingCellConfig->firstActiveDownlinkBWP_Id ? - *servingCellConfig->firstActiveDownlinkBWP_Id : 0; - sched_ctrl->active_bwp = bwpList && bwp_id > 0 ? bwpList->list.array[bwp_id - 1] : NULL; - const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; - const int ubwp_id = servingCellConfig && servingCellConfig->uplinkConfig && servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id ? - *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; - sched_ctrl->active_ubwp = ubwpList && ubwp_id > 0 ? ubwpList->list.array[ubwp_id - 1] : NULL; - sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_INACTIVE; - } - break; - - case BWP_SWITCH_INACTIVE: - break; - - default: - AssertFatal(1==0,"Invalid bwp switch state\n"); - break; - } -} - void schedule_nr_bwp_switch(module_id_t module_id, frame_t frame, sub_frame_t slot) { @@ -2954,16 +2907,21 @@ void schedule_nr_bwp_switch(module_id_t module_id, const NR_list_t *UE_list = &UE_info->list; // TODO: Implementation of a algorithm to perform: - // - the BWP switch trigger: sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_TO_START - // - the BWP selection: sched_ctrl->bwp_switch_info.next_bwp = bwp_id + // - DL BWP selection: sched_ctrl->next_dl_bwp_id = dl_bwp_id + // - UL BWP selection: sched_ctrl->next_ul_bwp_id = ul_bwp_id for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if(sched_ctrl->bwp_switch_info.bwp_switch_state > BWP_SWITCH_INACTIVE) { - nr_bwp_switch(module_id, frame, slot, UE_id, sched_ctrl->bwp_switch_info.next_bwp); + if (sched_ctrl->rrc_processing_timer == 0 && + UE_info->Msg4_ACKed[UE_id] == true && + ((sched_ctrl->next_dl_bwp_id >= 0 && sched_ctrl->active_bwp && sched_ctrl->active_bwp->bwp_Id != sched_ctrl->next_dl_bwp_id) || + (sched_ctrl->next_ul_bwp_id >= 0 && sched_ctrl->active_ubwp && sched_ctrl->active_ubwp->bwp_Id != sched_ctrl->next_ul_bwp_id))) { + + LOG_W(NR_MAC,"(%d.%d) [UE_id %d] Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", + frame, slot, UE_id, sched_ctrl->active_bwp->bwp_Id, sched_ctrl->next_dl_bwp_id, sched_ctrl->active_ubwp->bwp_Id, sched_ctrl->next_ul_bwp_id); + nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE_info->rnti[UE_id], sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); } } - } /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index b80b954b8c..4d82f51868 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -558,19 +558,6 @@ typedef struct NR_UE_ul_harq { NR_sched_pusch_t sched_pusch; } NR_UE_ul_harq_t; -typedef enum { - BWP_SWITCH_INACTIVE = 0, - BWP_SWITCH_TO_START, - BWP_SWITCH_RUNNING -} NR_BWP_switch_states_t; - -typedef struct NR_BWP_switch_info { - NR_BWP_Id_t current_bwp; - NR_BWP_Id_t next_bwp; - sub_frame_t bwp_switch_slot; - NR_BWP_switch_states_t bwp_switch_state; -} NR_BWP_switch_info_t; - /*! \brief scheduling control information set through an API */ #define MAX_CSI_REPORTS 48 typedef struct { @@ -579,8 +566,10 @@ typedef struct { /// the currently active BWP in UL NR_BWP_Uplink_t *active_ubwp; - /// the state of bwp switch procedure - NR_BWP_switch_info_t bwp_switch_info; + /// the next active BWP ID in DL + NR_BWP_Id_t next_dl_bwp_id; + /// the next active BWP ID in UL + NR_BWP_Id_t next_ul_bwp_id; /// CCE index and aggregation, should be coherent with cce_list NR_SearchSpace_t *search_space; diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index 9c06dfaff4..c8df5d4b5f 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -297,13 +297,14 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, const frame_t frameP, const sub_frame_t sub_frameP, const rnti_t rntiP, - const int bwp_id) { + const int dl_bwp_id, + const int ul_bwp_id) { struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[module_idP], rntiP); protocol_ctxt_t ctxt; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, GNB_FLAG_YES, rntiP, frameP, sub_frameP, 0); - nr_rrc_reconfiguration_req(ue_context_p, &ctxt, bwp_id); + nr_rrc_reconfiguration_req(ue_context_p, &ctxt, dl_bwp_id, ul_bwp_id); return 0; } diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index ab5f5fbc65..6a320123de 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -171,7 +171,8 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, const frame_t frameP, const sub_frame_t sub_frameP, const rnti_t rntiP, - const int bwp_id); + const int dl_bwp_id, + const int ul_bwp_id); int8_t nr_mac_rrc_data_ind( const module_id_t module_idP, @@ -188,7 +189,8 @@ int8_t nr_mac_rrc_data_ind( int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, protocol_ctxt_t *const ctxt_pP, - const int bwp_id); + const int dl_bwp_id, + const int ul_bwp_id); int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, const uint8_t *buffer, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3f47e41b0d..3d41787a2d 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1942,16 +1942,21 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, protocol_ctxt_t *const ctxt_pP, - const int bwp_id) { + const int dl_bwp_id, + const int ul_bwp_id) { uint8_t buffer[RRC_BUF_SIZE]; memset(buffer, 0, sizeof(buffer)); uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); NR_CellGroupConfig_t *masterCellGroup = ue_context_pP->ue_context.masterCellGroup; - *masterCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = bwp_id; - *masterCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = bwp_id; - *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = bwp_id; + if (dl_bwp_id >= 0) { + *masterCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = dl_bwp_id; + *masterCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = dl_bwp_id; + } + if (ul_bwp_id >= 0) { + *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; + } uint16_t size = do_RRCReconfiguration(ctxt_pP, buffer, From c587fe366d9db874e4703b63fc0188080e021961 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 6 May 2022 16:01:10 +0100 Subject: [PATCH 200/226] Improve log and cosmetic changes --- openair2/GNB_APP/gnb_config.c | 148 +++++++++--------- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 8 +- ...gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf | 4 +- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ea3133db76..bd3c3b8d2c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -382,84 +382,84 @@ void prepare_scd(NR_ServingCellConfig_t *scd) { scd->defaultDownlinkBWP_Id = CALLOC(1, sizeof(*scd->defaultDownlinkBWP_Id)); *scd->defaultDownlinkBWP_Id = 0; -for (int j = 0; j < NR_MAX_NUM_BWP; j++) { + for (int j = 0; j < NR_MAX_NUM_BWP; j++) { - // Downlink bandwidth part - NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp)); - bwp->bwp_Id = j+1; + // Downlink bandwidth part + NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp)); + bwp->bwp_Id = j+1; - // Allocate downlink dedicated bandwidth part and PDSCH structures - bwp->bwp_Common = calloc(1, sizeof(*bwp->bwp_Common)); - bwp->bwp_Common->pdcch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdcch_ConfigCommon)); - bwp->bwp_Common->pdsch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdsch_ConfigCommon)); - bwp->bwp_Dedicated = calloc(1, sizeof(*bwp->bwp_Dedicated)); - bwp->bwp_Dedicated->pdsch_Config = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config)); - bwp->bwp_Dedicated->pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup; - bwp->bwp_Dedicated->pdsch_Config->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup)); - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA)); - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup; + // Allocate downlink dedicated bandwidth part and PDSCH structures + bwp->bwp_Common = calloc(1, sizeof(*bwp->bwp_Common)); + bwp->bwp_Common->pdcch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdcch_ConfigCommon)); + bwp->bwp_Common->pdsch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdsch_ConfigCommon)); + bwp->bwp_Dedicated = calloc(1, sizeof(*bwp->bwp_Dedicated)); + bwp->bwp_Dedicated->pdsch_Config = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config)); + bwp->bwp_Dedicated->pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup; + bwp->bwp_Dedicated->pdsch_Config->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup)); + bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA)); + bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup; - // Allocate DL DMRS and PTRS configuration - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup)); - NR_DMRS_DownlinkConfig_t *NR_DMRS_DownlinkCfg = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; - NR_DMRS_DownlinkCfg->phaseTrackingRS=CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS)); - NR_DMRS_DownlinkCfg->phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup; - NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup)); - NR_PTRS_DownlinkConfig_t *NR_PTRS_DownlinkCfg = NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup; - NR_PTRS_DownlinkCfg->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->frequencyDensity)); - long *dl_rbs = CALLOC(2, sizeof(long)); - for (int i=0;i<2;i++) { - ASN_SEQUENCE_ADD(&NR_PTRS_DownlinkCfg->frequencyDensity->list, &dl_rbs[i]); + // Allocate DL DMRS and PTRS configuration + bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup)); + NR_DMRS_DownlinkConfig_t *NR_DMRS_DownlinkCfg = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; + NR_DMRS_DownlinkCfg->phaseTrackingRS=CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS)); + NR_DMRS_DownlinkCfg->phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup; + NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup)); + NR_PTRS_DownlinkConfig_t *NR_PTRS_DownlinkCfg = NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup; + NR_PTRS_DownlinkCfg->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->frequencyDensity)); + long *dl_rbs = CALLOC(2, sizeof(long)); + for (int i=0;i<2;i++) { + ASN_SEQUENCE_ADD(&NR_PTRS_DownlinkCfg->frequencyDensity->list, &dl_rbs[i]); + } + NR_PTRS_DownlinkCfg->timeDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->timeDensity)); + long *dl_mcs = CALLOC(3, sizeof(long)); + for (int i=0;i<3;i++) { + ASN_SEQUENCE_ADD(&NR_PTRS_DownlinkCfg->timeDensity->list, &dl_mcs[i]); + } + NR_PTRS_DownlinkCfg->epre_Ratio = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->epre_Ratio)); + NR_PTRS_DownlinkCfg->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->resourceElementOffset)); + *NR_PTRS_DownlinkCfg->resourceElementOffset = 0; + ASN_SEQUENCE_ADD(&scd->downlinkBWP_ToAddModList->list,bwp); + + // Allocate uplink structures + + NR_PUSCH_Config_t *pusch_Config = CALLOC(1, sizeof(*pusch_Config)); + + // Allocate UL DMRS and PTRS structures + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB)); + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup; + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); + NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; + NR_DMRS_UplinkConfig->phaseTrackingRS = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS)); + NR_DMRS_UplinkConfig->phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup; + NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup)); + NR_PTRS_UplinkConfig_t *NR_PTRS_UplinkConfig = NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup; + NR_PTRS_UplinkConfig->transformPrecoderDisabled = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled)); + NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity)); + long *n_rbs = CALLOC(2, sizeof(long)); + for (int i=0;i<2;i++) { + ASN_SEQUENCE_ADD(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity->list, &n_rbs[i]); + } + NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity)); + long *ptrs_mcs = CALLOC(3, sizeof(long)); + for (int i = 0; i < 3; i++) { + ASN_SEQUENCE_ADD(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity->list, &ptrs_mcs[i]); + } + NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset)); + *NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = 0; + + // UL bandwidth part + NR_BWP_Uplink_t *ubwp = CALLOC(1, sizeof(*ubwp)); + ubwp->bwp_Id = j+1; + ubwp->bwp_Common = CALLOC(1, sizeof(*ubwp->bwp_Common)); + ubwp->bwp_Dedicated = CALLOC(1, sizeof(*ubwp->bwp_Dedicated)); + + ubwp->bwp_Dedicated->pusch_Config = CALLOC(1, sizeof(*ubwp->bwp_Dedicated->pusch_Config)); + ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; + ubwp->bwp_Dedicated->pusch_Config->choice.setup = pusch_Config; + + ASN_SEQUENCE_ADD(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,ubwp); } - NR_PTRS_DownlinkCfg->timeDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->timeDensity)); - long *dl_mcs = CALLOC(3, sizeof(long)); - for (int i=0;i<3;i++) { - ASN_SEQUENCE_ADD(&NR_PTRS_DownlinkCfg->timeDensity->list, &dl_mcs[i]); - } - NR_PTRS_DownlinkCfg->epre_Ratio = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->epre_Ratio)); - NR_PTRS_DownlinkCfg->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->resourceElementOffset)); - *NR_PTRS_DownlinkCfg->resourceElementOffset = 0; - ASN_SEQUENCE_ADD(&scd->downlinkBWP_ToAddModList->list,bwp); - - // Allocate uplink structures - - NR_PUSCH_Config_t *pusch_Config = CALLOC(1, sizeof(*pusch_Config)); - - // Allocate UL DMRS and PTRS structures - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB)); - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup; - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); - NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; - NR_DMRS_UplinkConfig->phaseTrackingRS = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS)); - NR_DMRS_UplinkConfig->phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup; - NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup)); - NR_PTRS_UplinkConfig_t *NR_PTRS_UplinkConfig = NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup; - NR_PTRS_UplinkConfig->transformPrecoderDisabled = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled)); - NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity)); - long *n_rbs = CALLOC(2, sizeof(long)); - for (int i=0;i<2;i++) { - ASN_SEQUENCE_ADD(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity->list, &n_rbs[i]); - } - NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity)); - long *ptrs_mcs = CALLOC(3, sizeof(long)); - for (int i = 0; i < 3; i++) { - ASN_SEQUENCE_ADD(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity->list, &ptrs_mcs[i]); - } - NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset)); - *NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = 0; - - // UL bandwidth part - NR_BWP_Uplink_t *ubwp = CALLOC(1, sizeof(*ubwp)); - ubwp->bwp_Id = j+1; - ubwp->bwp_Common = CALLOC(1, sizeof(*ubwp->bwp_Common)); - ubwp->bwp_Dedicated = CALLOC(1, sizeof(*ubwp->bwp_Dedicated)); - - ubwp->bwp_Dedicated->pusch_Config = CALLOC(1, sizeof(*ubwp->bwp_Dedicated->pusch_Config)); - ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; - ubwp->bwp_Dedicated->pusch_Config->choice.setup = pusch_Config; - - ASN_SEQUENCE_ADD(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,ubwp); -} } /* This function checks dedicated serving cell configuration and performs fixes as needed */ diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 9dff368ccc..5eb6db2cdf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -467,7 +467,7 @@ int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, rnti_t rnti, NR_S const uint16_t sf_ahead = 6/(0x01<0); const uint16_t sl_ahead = sf_ahead * (0x01<rrc_processing_timer = (rrc_reconfiguration_delay<DL_req[CC_id].dl_tti_request_body; NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? - &sched_ctrl->active_bwp->bwp_Common->genericParameters: + &sched_ctrl->active_bwp->bwp_Common->genericParameters : &gNB_mac->common_channels[0].ServingCellConfigCommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters; for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){ nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; @@ -2836,15 +2836,15 @@ void nr_mac_update_timers(module_id_t module_id, // If needed, update the Dedicated BWP const int current_bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; const int current_ubwp_id = sched_ctrl->active_ubwp ? sched_ctrl->active_ubwp->bwp_Id : 0; - if(spCellConfigDedicated && + if (spCellConfigDedicated && spCellConfigDedicated->downlinkBWP_ToAddModList && spCellConfigDedicated->uplinkConfig && spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { - if(*spCellConfigDedicated->firstActiveDownlinkBWP_Id != current_bwp_id) { + if (*spCellConfigDedicated->firstActiveDownlinkBWP_Id != current_bwp_id) { sched_ctrl->active_bwp = spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[*spCellConfigDedicated->firstActiveDownlinkBWP_Id - 1]; LOG_I(NR_MAC, "Changing to DL-BWP %li\n", sched_ctrl->active_bwp->bwp_Id); } - if(*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != current_ubwp_id) { + if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != current_ubwp_id) { sched_ctrl->active_ubwp = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id - 1]; LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); } diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf index 2a84743a0c..3d93f2cfab 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf @@ -175,7 +175,7 @@ servingCellConfigDedicated = ({ # BWP-Downlink # BWP 1 Configuration dl_bwp-Id_1 = 1; - dl_bwp1_locationAndBandwidth = 1099; // RBstart=0, L=217 (80 MHz BW) + dl_bwp1_locationAndBandwidth = 1099; // RBstart=0, L=273 (100 MHz BW) # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 dl_bwp1_subcarrierSpacing = 1; @@ -192,7 +192,7 @@ servingCellConfigDedicated = ({ # BWP-Uplink # BWP 1 Configuration ul_bwp-Id_1 = 1; - ul_bwp1_locationAndBandwidth = 1099; // RBstart=0, L=217 (80 MHz BW) + ul_bwp1_locationAndBandwidth = 1099; // RBstart=0, L=273 (100 MHz BW) # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 ul_bwp1_subcarrierSpacing = 1; From d7795c9dffe91fb81509c11a6f2dcec921b3f735 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Fri, 6 May 2022 16:15:43 +0100 Subject: [PATCH 201/226] Fix build after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a8ee9f4b98..be3c2beb26 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2878,6 +2878,7 @@ void nr_mac_update_timers(module_id_t module_id, int dci_format = get_dci_format(sched_ctrl); const uint8_t num_dmrs_cdm_grps_no_data = (ubwp || ubwpd) ? 1 : 2; + const uint8_t nrOfLayers = 1; const int utda = ubwp && preferred_ul_tda[ubwp->bwp_Id][slot] >= 0 ? preferred_ul_tda[ubwp->bwp_Id][slot] : (ups->time_domain_allocation >= 0 ? ups->time_domain_allocation : 0); @@ -2888,6 +2889,7 @@ void nr_mac_update_timers(module_id_t module_id, dci_format, utda, num_dmrs_cdm_grps_no_data, + nrOfLayers, ups); } } From 421ca8aed5634650363e7ca743bd4d742b8b9cdf Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 4 May 2022 11:36:14 +0100 Subject: [PATCH 202/226] Clean up of unused test cases in NSA with B210 --- ci-scripts/xml_files/fr1_nsa_quectel.xml | 33 +++--------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index 0f8c90abdf..99c0e1757b 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -34,8 +34,8 @@ 050000 050001 000001 - 070003 - 070002 + 070000 + 070001 000001 050000 050001 @@ -52,14 +52,12 @@ yes - Terminate_UE Terminate Quectel idefix - Initialize_eNB Initialize eNB @@ -70,7 +68,6 @@ yes - Initialize_eNB Initialize gNB @@ -92,7 +89,6 @@ 20 - Ping Ping: 20pings in 20sec @@ -112,28 +108,6 @@ - Iperf - iperf (DL/30Mbps/UDP)(30 sec)(single-ue profile) - -u -b 30M -t 30 - DL - idefix - 1 - 95 - single-ue - - - - Iperf - iperf (DL/90Mbps/UDP)(30 sec)(single-ue profile) - -u -b 90M -t 30 - DL - idefix - 1 - 95 - single-ue - - - Iperf iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) -u -b 125M -t 60 @@ -144,7 +118,7 @@ single-ue - + Iperf iperf (UL/8Mbps/UDP)(60 sec)(single-ue profile) -u -b 8M -t 60 @@ -155,7 +129,6 @@ single-ue - Terminate_eNB Terminate eNB From c6bedb6c27052a7bb1ca4c1a9b5035c64ef0ebf9 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 4 May 2022 11:39:59 +0100 Subject: [PATCH 203/226] Increase iPerf packet loss and bitrate thresholds to make RAN-NSA-B200-Module-LTEBOX test green (due to UE host performance) --- ci-scripts/xml_files/fr1_nsa_quectel.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index 99c0e1757b..a7fd0fc0d7 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -113,8 +113,8 @@ -u -b 125M -t 60 DL idefix - 1 - 95 + 25 + 80 single-ue From ad8f99dc03435180fa7a23d7d355aedfc7cd4f5a Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Sun, 8 May 2022 02:22:52 +0100 Subject: [PATCH 204/226] Increase iPerf packet loss and bitrate thresholds to make RAN-NSA-B200-Module-LTEBOX-Container test green (due to UE host performance) --- ci-scripts/xml_files/container_nsa_b200_quectel.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 47a939f63c..8d04be3efd 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -142,8 +142,8 @@ -u -b 125M -t 60 -i 1 -fm DL idefix - 1 - 95 + 25 + 80 single-ue From 3e3d73ef935a05a6de626031cb9dec7eab181a78 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 May 2022 10:01:09 +0200 Subject: [PATCH 205/226] Install UHD 4.2 for U18/20/22 --- cmake_targets/tools/build_helper | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 0d2c82d62e..179e2de428 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -381,7 +381,7 @@ check_install_usrp_uhd_driver(){ $SUDO apt-get remove libuhd3.14.1 -y || true $SUDO apt-get remove libuhd3.15.0 -y || true local distribution=$(get_distribution_release) - if [[ "$distribution" == "ubuntu18.04" ]]; then + if [[ "$distribution" == "ubuntu18.04" || "$distribution" == "ubuntu20.04" || "$distribution" == "ubuntu22.04" ]]; then $SUDO apt-get remove libuhd4.0.0 -y || true $SUDO apt-get remove libuhd4.1.0 -y || true fi @@ -411,12 +411,14 @@ check_install_usrp_uhd_driver(){ done $SUDO apt-get update $SUDO apt-get -y install python-tk libboost-all-dev libusb-1.0-0-dev - if [[ "$distribution" == "ubuntu16.04" ]]; then + case "$(get_distribution_release)" in + "ubuntu16.04") $SUDO apt-get -y install libuhd-dev libuhd3.15.0 uhd-host - fi - if [[ "$distribution" == "ubuntu18.04" ]]; then - $SUDO apt-get -y install libuhd-dev libuhd4.1.0 uhd-host - fi + ;; + "ubuntu18.04" | "ubuntu20.04" | "ubuntu22.04") + $SUDO apt-get -y install libuhd-dev libuhd4.2.0 uhd-host + ;; + esac elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then if [ $IS_CONTAINER -eq 0 ] then From b37e5e552bf0800e01e987273b0f610eebe8eb07 Mon Sep 17 00:00:00 2001 From: Manish Date: Wed, 27 Apr 2022 05:31:12 +0000 Subject: [PATCH 206/226] help menu updated in document for native architecture. Compilation steps corrected on Ubuntu 20. Signed-off-by: Manish --- doc/BUILD.md | 1 + doc/TESTING_5GSA_setup.md | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index a52ce98cb5..70d69f5afd 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -193,6 +193,7 @@ Using the help option of the build script you can get the list of available opti | --UE | maintained and tested in CI | build `lte-uesoftmodem` the LTE UE | | --gNB | maintained and tested in CI | build `nr-softmodem` the 5G gNodeB | | --nrUE | maintained and tested in CI | build `nr-uesoftmodem` the 5G UE | +| --arch-native | maintained | build with native architecture optimization | | --usrp-recplay | deprecated | use the USRP configuration parameters to use the record player. | | --build-lib | maintained | build optional shared library(ies), which can then be loaded at run time via command line option. Use the --help option to get the list of supported optional libraries. `all` can be used to build all available optional libraries. | | --UE-conf-nvram | maintained | Specifies the path to the input file used by the conf2uedata utility. defaults to [openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf](../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf) | diff --git a/doc/TESTING_5GSA_setup.md b/doc/TESTING_5GSA_setup.md index 9b27549df4..4b86e12297 100644 --- a/doc/TESTING_5GSA_setup.md +++ b/doc/TESTING_5GSA_setup.md @@ -82,15 +82,7 @@ To get the code and build the gNB executable: git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git git checkout develop - # Install dependencies in Ubuntu 20.04 - cd - cd openairinterface5g/ - source oaienv - cd cmake_targets/ - ./install_external_packages.ubuntu20 - # Build OAI gNB - cd cd openairinterface5g/ source oaienv cd cmake_targets/ From d6f79071abdf7ba6e5fce8e7272263c81475f2d4 Mon Sep 17 00:00:00 2001 From: Manish Date: Tue, 10 May 2022 02:52:56 +0000 Subject: [PATCH 207/226] gNB Build Section Updated --- doc/TESTING_5GSA_setup.md | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/doc/TESTING_5GSA_setup.md b/doc/TESTING_5GSA_setup.md index 4b86e12297..357c62c813 100644 --- a/doc/TESTING_5GSA_setup.md +++ b/doc/TESTING_5GSA_setup.md @@ -50,7 +50,7 @@ At the moment of writing this document interoperability with the following COTS ## 1.1 gNB build and configuration To get the code and build the gNB executable: -### Ubuntu 18.04 +### Build gNB ```bash git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git git checkout develop @@ -61,34 +61,6 @@ To get the code and build the gNB executable: ./build_oai --gNB -w USRP ``` -### Ubuntu 20.04 -```bash - # Build UHD from source - # https://files.ettus.com/manual/page_build_guide.html - sudo apt-get install libboost-all-dev libusb-1.0-0-dev doxygen python3-docutils python3-mako python3-numpy python3-requests python3-ruamel.yaml python3-setuptools cmake build-essential - - git clone https://github.com/EttusResearch/uhd.git - cd uhd/host - mkdir build - cd build - cmake ../ - make -j 4 - make test # This step is optional - sudo make install - sudo ldconfig - sudo uhd_images_downloader - - - git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git - git checkout develop - - # Build OAI gNB - cd openairinterface5g/ - source oaienv - cd cmake_targets/ - ./build_oai --gNB -w USRP -``` - A reference configuration file for the **monolithic** gNB is provided [here](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf). From 1fbc7e080b78b992e9d1426620a3fe9133825923 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 May 2022 08:50:29 +0200 Subject: [PATCH 208/226] addressing review --- doc/RUNMODEM.md | 2 +- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index f741ae67d5..b291bdf2dd 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -222,7 +222,7 @@ This image shows an example of gNB 5G MIMO logical antenna port configuration. I The basic element is a dual-polarized antenna, therefore the minimal DL MIMO setup with two logical antenna ports would consist of two cross-polarized antenna elements. In a single panel configuration, as the one in the picture, this element can be repeated vertiacally and/or horizontally to form an equi-spaced 1D or 2D array. The values N1 and N2 represent the number of antenna ports in the two dimensions and the supported configurations are specified in Section 5.2.2.2.1 of TS 38.214. -The DL logical antenna port configuration can be selected thorugh configuration file. `pdsch_AntennaPorts_N1` can be used to set N1 parameter, `pdsch_AntennaPorts_N2` to set N2 and `pdsch_AntennaPorts_XP` to set the cross-polarization configuration (1 for single pol, 2 for cross-pol). To be noted that if XP is 1 but N1 and/or N2 are larger than 1, this would result in a non-standard configuration and the PMI selected would be the identity matrix regardless of CSI report. The default value for each of these parameters is 1. +The DL logical antenna port configuration can be selected through configuration file. `pdsch_AntennaPorts_N1` can be used to set N1 parameter, `pdsch_AntennaPorts_N2` to set N2 and `pdsch_AntennaPorts_XP` to set the cross-polarization configuration (1 for single pol, 2 for cross-pol). To be noted that if XP is 1 but N1 and/or N2 are larger than 1, this would result in a non-standard configuration and the PMI selected would be the identity matrix regardless of CSI report. The default value for each of these parameters is 1. # Additional links diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 793d7cb5ac..d1c376d793 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -209,7 +209,7 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts, int pusch_AntennaPorts, - NR_ServingCellConfigCommon_t *scc); + NR_ServingCellConfigCommon_t *scc); int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, From 340531038c464cb87257b95199e1c4603f896685 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 May 2022 15:21:08 +0200 Subject: [PATCH 209/226] bugfix: n1 and n2 for 2 ports --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 6d23f2f1eb..a7c736c813 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -503,6 +503,8 @@ void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, if(codebookConfig->codebookType.choice.type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) { if(codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { + csi_report->N1 = 1; + csi_report->N2 = 1; if (i==0) csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=2; if (i==1) From a582ac99e5cf71f000e063fc20c5026aa3a2f099 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 May 2022 09:19:27 +0200 Subject: [PATCH 210/226] Trigger Amarisoft in NSA tests --- ci-scripts/Jenkinsfile-trig-nsa | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ci-scripts/Jenkinsfile-trig-nsa b/ci-scripts/Jenkinsfile-trig-nsa index 772b34231a..3616b2c404 100644 --- a/ci-scripts/Jenkinsfile-trig-nsa +++ b/ci-scripts/Jenkinsfile-trig-nsa @@ -113,6 +113,21 @@ pipeline { GitPostArgs += jobName + ' ' + build_url + ' ' + build_id + ' ' + jobResult + ' ' echo GitPostArgs + //calling SA-AmariS + jobName = "RAN-SA-AmariS-CN5G" + jobStatus = build job: jobName, wait : true, propagate : false, parameters: [ + string(name: 'eNB_MR', value: String.valueOf(MR)), + string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), + string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), + string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), + booleanParam(name: 'eNB_mergeRequest', value: Boolean.valueOf(ALLOW_MERGE)) + ] + jobResult = jobStatus.getResult() + build_url = jobStatus.getAbsoluteUrl() + build_id = jobStatus.getNumber().toString() + GitPostArgs += jobName + ' ' + build_url + ' ' + build_id + ' ' + jobResult + ' ' + echo GitPostArgs + //calling OAIUE N310-X300 jobName = "RAN-SA-OAIUE-N310-X300-CN5G" jobStatus = build job: jobName, wait : true, propagate : false, parameters: [ From 270c540c3cbf75eb452042501ae35dce68dfa89f Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 11 May 2022 15:09:35 +0100 Subject: [PATCH 211/226] Minor clean up in function mac_rrc_nr_data_req --- openair2/RRC/NR/L2_nr_interface.c | 87 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index c8df5d4b5f..952f32fb10 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -219,78 +219,75 @@ uint16_t mac_rrc_nr_data_req(const module_id_t Mod_idP, LOG_D(RRC,"[eNB %d] mac_rrc_data_req to SRB ID=%ld\n",Mod_idP,Srb_id); #endif - // MIBCH - if ((Srb_id & RAB_OFFSET) == MIBCH) { + // MIBCH + if ((Srb_id & RAB_OFFSET) == MIBCH) { - asn_enc_rval_t enc_rval; - uint8_t sfn_msb = (uint8_t)((frameP>>4)&0x3f); - rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[Mod_idP]->carrier; - NR_BCCH_BCH_Message_t *mib = &carrier->mib; + asn_enc_rval_t enc_rval; + uint8_t sfn_msb = (uint8_t)((frameP>>4)&0x3f); + rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[Mod_idP]->carrier; + NR_BCCH_BCH_Message_t *mib = &carrier->mib; - // Currently we are getting the pdcch_ConfigSIB1 from the configuration file. - // Uncomment this function for a dynamic pdcch_ConfigSIB1. - //channel_bandwidth_t min_channel_bw = bw_10MHz; // Must be obtained based on TS 38.101-1 Table 5.3.5-1 - //generate_pdcch_ConfigSIB1(carrier->pdcch_ConfigSIB1, - // *carrier->servingcellconfigcommon->ssbSubcarrierSpacing, - // carrier->mib.message.choice.mib->subCarrierSpacingCommon, - // min_channel_bw); + // Currently we are getting the pdcch_ConfigSIB1 from the configuration file. + // Uncomment this function for a dynamic pdcch_ConfigSIB1. + //channel_bandwidth_t min_channel_bw = bw_10MHz; // Must be obtained based on TS 38.101-1 Table 5.3.5-1 + //generate_pdcch_ConfigSIB1(carrier->pdcch_ConfigSIB1, + // *carrier->servingcellconfigcommon->ssbSubcarrierSpacing, + // carrier->mib.message.choice.mib->subCarrierSpacingCommon, + // min_channel_bw); - mib->message.choice.mib->pdcch_ConfigSIB1.controlResourceSetZero = carrier->pdcch_ConfigSIB1->controlResourceSetZero; - mib->message.choice.mib->pdcch_ConfigSIB1.searchSpaceZero = carrier->pdcch_ConfigSIB1->searchSpaceZero; + mib->message.choice.mib->pdcch_ConfigSIB1.controlResourceSetZero = carrier->pdcch_ConfigSIB1->controlResourceSetZero; + mib->message.choice.mib->pdcch_ConfigSIB1.searchSpaceZero = carrier->pdcch_ConfigSIB1->searchSpaceZero; - mib->message.choice.mib->systemFrameNumber.buf[0] = sfn_msb << 2; - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_BCCH_BCH_Message, - NULL, - (void *) mib, - carrier->MIB, - 24); - LOG_D(NR_RRC, "Encoded MIB for frame %d sfn_msb %d (%p), bits %lu\n", frameP, sfn_msb, carrier->MIB, - enc_rval.encoded); - buffer_pP[0] = carrier->MIB[0]; - buffer_pP[1] = carrier->MIB[1]; - buffer_pP[2] = carrier->MIB[2]; - LOG_D(NR_RRC, "MIB PDU buffer_pP[0]=%x , buffer_pP[1]=%x, buffer_pP[2]=%x\n", buffer_pP[0], buffer_pP[1], - buffer_pP[2]); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - return (3); - } + mib->message.choice.mib->systemFrameNumber.buf[0] = sfn_msb << 2; + enc_rval = uper_encode_to_buffer(&asn_DEF_NR_BCCH_BCH_Message, + NULL, + (void *) mib, + carrier->MIB, + 24); + LOG_D(NR_RRC, "Encoded MIB for frame %d sfn_msb %d (%p), bits %lu\n", frameP, sfn_msb, carrier->MIB, + enc_rval.encoded); + buffer_pP[0] = carrier->MIB[0]; + buffer_pP[1] = carrier->MIB[1]; + buffer_pP[2] = carrier->MIB[2]; + LOG_D(NR_RRC, "MIB PDU buffer_pP[0]=%x , buffer_pP[1]=%x, buffer_pP[2]=%x\n", buffer_pP[0], buffer_pP[1], + buffer_pP[2]); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + return 3; + } // TODO BCCH SIB1 SIBs - if ((Srb_id & RAB_OFFSET ) == BCCH) { - memcpy(&buffer_pP[0], - RC.nrrrc[Mod_idP]->carrier.SIB1, - RC.nrrrc[Mod_idP]->carrier.sizeof_SIB1); - + if ((Srb_id & RAB_OFFSET) == BCCH) { + memcpy(&buffer_pP[0], RC.nrrrc[Mod_idP]->carrier.SIB1, RC.nrrrc[Mod_idP]->carrier.sizeof_SIB1); return RC.nrrrc[Mod_idP]->carrier.sizeof_SIB1; } // CCCH - if( (Srb_id & RAB_OFFSET ) == CCCH) { + if ((Srb_id & RAB_OFFSET) == CCCH) { + LOG_D(NR_RRC,"[gNB %d] Frame %d CCCH request (Srb_id %ld)\n", Mod_idP, frameP, Srb_id); char *payload_pP; - uint16_t Sdu_size = 0; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[Mod_idP], rnti); LOG_D(NR_RRC,"[gNB %d] Frame %d CCCH request (Srb_id %ld)\n", Mod_idP, frameP, Srb_id); + if (ue_context_p == NULL) { + LOG_E(NR_RRC,"[gNB %d] Frame %d CCCH request but no ue_context\n", Mod_idP, frameP); + return 0; + } - AssertFatal(ue_context_p!=NULL,"failed to get ue_context, rnti %x\n",rnti); uint16_t payload_size = ue_context_p->ue_context.Srb0.Tx_buffer.payload_size; - // check if data is there for MAC if (payload_size > 0) { payload_pP = ue_context_p->ue_context.Srb0.Tx_buffer.Payload; LOG_D(NR_RRC,"[gNB %d] CCCH has %d bytes (dest: %p, src %p)\n", Mod_idP, payload_size, buffer_pP, payload_pP); // Fill buffer memcpy((void *)buffer_pP, (void*)payload_pP, payload_size); - Sdu_size = payload_size; ue_context_p->ue_context.Srb0.Tx_buffer.payload_size = 0; } - return Sdu_size; + return payload_size; } - return(0); - + return 0; } int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, From 0217cd50deef2fe85952527986958cdf4a3d295c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 11 May 2022 15:46:25 +0100 Subject: [PATCH 212/226] Update in documentation --- .vscode/launch.json | 1 - doc/FEATURE_SET.md | 5 + doc/RUN_NR_multiple_BWPs.md | 33 +- .../gnb.band78.tm1.106PRB.usrpn300.SCD.conf | 348 ------------------ 4 files changed, 19 insertions(+), 368 deletions(-) delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf diff --git a/.vscode/launch.json b/.vscode/launch.json index 250adbbb54..8be6915763 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,7 +4,6 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { "name": "(gdb) Launch", "type": "cppdbg", diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index a289c6d17e..d0856b415d 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -332,6 +332,9 @@ The following features are valid for the gNB and the 5G-NR UE. - evalution of RSRP report - evaluation of CQI report - MAC scheduling of SR reception +- Bandwidth part (BWP) operation + - Handle multiple dedicated BWPs + - BWP switching through RRCReconfiguration method **gNB RLC** - Send/Receive operations according to 38.322 Rel.16 @@ -493,6 +496,8 @@ The following features are valid for the gNB and the 5G-NR UE. - Configuration of fapi PDU according to DCI * Scheduler procedures for SRS transmission - Periodic SRS transmission +* Bandwidth part (BWP) operation + - Operation in configured dedicated BWP through RRCSetup or RRCReconfiguration **UE RLC** diff --git a/doc/RUN_NR_multiple_BWPs.md b/doc/RUN_NR_multiple_BWPs.md index f79dc21947..2c2c2fcf25 100644 --- a/doc/RUN_NR_multiple_BWPs.md +++ b/doc/RUN_NR_multiple_BWPs.md @@ -9,9 +9,9 @@ ## Bandwidth part (BWP) ## Bandwidth Part (BWP) is a set of contiguous Resource Blocks in the resource grid. -Parameters of a Bandwidth Part are communicated to UE using RRC parameters: BWP-Downlink and BWP-Uplink. +Parameters of a BWP are communicated to UE using RRC parameters: BWP-Downlink and BWP-Uplink. -A UE can be configured with a set of 4 BWPs in uplink (UL) and downlink (DL) direction. But only 1 BWP can be active in UL and DL direction at a given time. +A UE can be configured with a set of 4 BWPs in uplink (UL) and downlink (DL) direction (3GPP TS 38.331 Annex B.2 Description of BWP configuration options). But only 1 BWP can be active in UL and DL direction at a given time. # Procedure to run multiple dedicated BWPs # @@ -21,36 +21,31 @@ To configure multiple BWPs, add the following parameters to the gNB configuratio ## Setup of the Configuration files ## ``` - firstActiveDownlinkBWP-Id = 1; #BWP-Id - defaultDownlinkBWP-Id = 1; #BWP-Id - firstActiveUplinkBWP-Id = 1; #BWP-Id + firstActiveDownlinkBWP-Id = 1; #BWP-Id + defaultDownlinkBWP-Id = 1; #BWP-Id + firstActiveUplinkBWP-Id = 1; #BWP-Id ``` Each dedicated BWP must have: ``` - # BWP 1 Configuration - bwp-Id_1 = 1; - bwp1_locationAndBandwidth = 28908; // RBstart=33,L=106 - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - bwp1_subcarrierSpacing = 1; + # BWP 1 Configuration + dl_bwp-Id_1 = 1; + dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp1_subcarrierSpacing = 1; ``` - Find these parameters in this configuration file: "targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf" - -### NOTE: - * For changing bandwidth, 'dl_carrierBandwidth' and 'ul_carrierBandwidth' must be modified according - to the bandwidth of the BWP - * Currently only 'firstActiveDownlinkBWP-Id' is used to configure both DL and UL BWPs + Find these parameters in this configuration file: "targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf" # Testing gNB and UE in RF simulator ## gNB command: ``` - sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf --rfsim --phy-test -d + sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim --sa ``` ## UE command: ``` - sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --rfsim --phy-test -d + sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --nokrnmod --rfsim --sa --uicc0.imsi 208990000000001 ``` \ No newline at end of file diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf deleted file mode 100644 index 2d8886bc46..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.SCD.conf +++ /dev/null @@ -1,348 +0,0 @@ -Active_gNBs = ( "gNB-Eurecom-5GNRBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -gNBs = -( - { - ////////// Identification parameters: - gNB_ID = 0xe00; - - cell_type = "CELL_MACRO_GNB"; - - gNB_name = "gNB-Eurecom-5GNRBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = 1; - - plmn_list = ({mcc = 208; mnc = 93; mnc_length = 2;}); - - tr_s_preference = "local_mac" - - ////////// Physical parameters: - - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; - min_rxtxtime = 6; - - servingCellConfigCommon = ( - { - #spCellConfigCommon - - physCellId = 0; - -# downlinkConfigCommon - #frequencyInfoDL - # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP), points to Subcarrier 0 of RB#10 of SSB block - absoluteFrequencySSB = 641032; - dl_frequencyBand = 78; - # this is 3600 MHz - dl_absoluteFrequencyPointA = 640000; - #scs-SpecificCarrierList - dl_offstToCarrier = 0; -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_subcarrierSpacing = 1; - dl_carrierBandwidth = 106; //when changing BWPs, change this also to the same RBs - #initialDownlinkBWP - #genericParameters - # this is RBstart=33 (Start RB of SSB block),L=24 (275*(L-1))+RBstart - initialDLBWPlocationAndBandwidth = 6358; #6368; -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - initialDLBWPsubcarrierSpacing = 1; - #pdcch-ConfigCommon - initialDLBWPcontrolResourceSetZero = 0; #12; - initialDLBWPsearchSpaceZero = 0; - #pdsch-ConfigCommon - #pdschTimeDomainAllocationList (up to 16 entries) - initialDLBWPk0_0 = 0; # used for (full) DL slot - initialDLBWPmappingType_0 = 0; # 0=typeA,1=typeB - initialDLBWPstartSymbolAndLength_0 = 40; # this is SS=1,L=13 - - initialDLBWPk0_1 = 0; # used for DL part mixed slot - initialDLBWPmappingType_1 = 0; - initialDLBWPstartSymbolAndLength_1 = 57; # this is SS=1,L=5 - - #uplinkConfigCommon - #frequencyInfoUL - ul_frequencyBand = 78; - #scs-SpecificCarrierList - ul_offstToCarrier = 0; -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_subcarrierSpacing = 1; - ul_carrierBandwidth = 106; //when changing BWPs, change this also to the same RBs - pMax = 20; - #initialUplinkBWP - #genericParameters - initialULBWPlocationAndBandwidth = 6358;#6368; -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - initialULBWPsubcarrierSpacing = 1; - #rach-ConfigCommon - #rach-ConfigGeneric - prach_ConfigurationIndex = 98; -#prach_msg1_FDM -#0 = one, 1=two, 2=four, 3=eight - prach_msg1_FDM = 0; - prach_msg1_FrequencyStart = 0; - zeroCorrelationZoneConfig = 13; - preambleReceivedTargetPower = -118; -#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) - preambleTransMax = 6; -#powerRampingStep -# 0=dB0,1=dB2,2=dB4,3=dB6 - powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; -#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR -#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 - ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; -#ra_ContentionResolutionTimer -#(0..7) 8,16,24,32,40,48,56,64 - ra_ContentionResolutionTimer = 7; - rsrp_ThresholdSSB = 19; -#prach-RootSequenceIndex_PR -#1 = 839, 2 = 139 - prach_RootSequenceIndex_PR = 2; - prach_RootSequenceIndex = 1; - # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex - # - msg1_SubcarrierSpacing = 1, -# restrictedSetConfig -# 0=unrestricted, 1=restricted type A, 2=restricted type B - restrictedSetConfig = 0, - - # pusch-ConfigCommon (up to 16 elements) - initialULBWPk2_0 = 6; # used for (full) UL slot - initialULBWPmappingType_0 = 1 - initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13 - - initialULBWPk2_1 = 6; # used for UL part mixed slot - initialULBWPmappingType_1 = 1; - initialULBWPstartSymbolAndLength_1 = 69; # this is SS=10 L=2 - - initialULBWPk2_2 = 7; # used for Msg.3 during RA - initialULBWPmappingType_2 = 1; - initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4 - - msg3_DeltaPreamble = 1; - p0_NominalWithGrant =-90; - -# pucch-ConfigCommon setup : -# pucchGroupHopping -# 0 = neither, 1= group hopping, 2=sequence hopping - pucchGroupHopping = 0; - hoppingId = 40; - p0_nominal = -90; -# ssb_PositionsInBurs_BitmapPR -# 1=short, 2=medium, 3=long - ssb_PositionsInBurst_PR = 2; - ssb_PositionsInBurst_Bitmap = 0x1; - -# ssb_periodicityServingCell -# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 - ssb_periodicityServingCell = 2; - -# dmrs_TypeA_position -# 0 = pos2, 1 = pos3 - dmrs_TypeA_Position = 0; - -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - subcarrierSpacing = 1; - - - #tdd-UL-DL-ConfigurationCommon -# subcarrierSpacing -# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - referenceSubcarrierSpacing = 1; - # pattern1 - # dl_UL_TransmissionPeriodicity - # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 - dl_UL_TransmissionPeriodicity = 6; - nrofDownlinkSlots = 7; - nrofDownlinkSymbols = 6; - nrofUplinkSlots = 2; - nrofUplinkSymbols = 4; - - ssPBCH_BlockPower = -25; - } - - ); - - -# Dedicated Serving Cell Configuration -servingCellConfigDedicated = ({ - # BWP-Downlink - # BWP 1 Configuration - dl_bwp-Id_1 = 1; - dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp1_subcarrierSpacing = 1; - - # BWP 2 Configuration - dl_bwp-Id_2 = 2; - dl_bwp2_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp2_subcarrierSpacing = 1; - - # BWP 3 Configuration - dl_bwp-Id_3 = 3; - dl_bwp3_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp3_subcarrierSpacing = 1; - - # BWP 4 Configuration - dl_bwp-Id_4 = 4; - dl_bwp4_locationAndBandwidth = 22299; // RBstart=24, L=82 - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp4_subcarrierSpacing = 1; - - firstActiveDownlinkBWP-Id = 1; #BWP-Id - defaultDownlinkBWP-Id = 1; #BWP-Id - - # bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30, - # ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500, - # ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8, - # spare7, spare6, spare5, spare4, spare3, spare2, spare1 } - - # UplinkConfig - # BWP-Uplink - # BWP 1 Configuration - ul_bwp-Id_1 = 1; - ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp1_subcarrierSpacing = 1; - - # BWP 2 Configuration - ul_bwp-Id_2 = 2; - ul_bwp2_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp2_subcarrierSpacing = 1; - - # BWP 3 Configuration - ul_bwp-Id_3 = 3; - ul_bwp3_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp3_subcarrierSpacing = 1; - - # BWP 4 Configuration - ul_bwp-Id_4 = 4; - ul_bwp4_locationAndBandwidth = 22299; // RBstart=24, L=82 - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp4_subcarrierSpacing = 1; - - firstActiveUplinkBWP-Id = 1; #BWP-Id - } -); - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.12.26"; - ipv6 = "192:168:30::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - - GNB_INTERFACE_NAME_FOR_S1_MME = "eth0"; - GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.111/24"; - GNB_INTERFACE_NAME_FOR_S1U = "eth0"; - GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.111/24"; - GNB_PORT_FOR_S1U = 2152; # Spec 2152 - }; - } -); - -MACRLCs = ( - { - num_cc = 1; - tr_s_preference = "local_L1"; - tr_n_preference = "local_RRC"; - } -); - -L1s = ( - { - num_cc = 1; - tr_n_preference = "local_mac"; - pusch_proc_threads = 8; - } -); - -RUs = ( - { - local_rf = "yes" - nb_tx = 1 - nb_rx = 1 - att_tx = 0 - att_rx = 0; - bands = [7]; - max_pdschReferenceSignalPower = -27; - max_rxgain = 50; - eNB_instances = [0]; - ## beamforming 1x2 matrix: 1 layer x 2 antennas - #bf_weights = [0x00007fff, 0x00007fff]; - ## beamforming 1x4 matrix: 1 layer x 4 antennas - #bf_weights = [0x00007fff, 0x0000,0x0000, 0x0000]; - ## beamforming 2x2 matrix: - #bf_weights = [0x00007fff, 0x00000000, 0x00000000, 0x00007fff]; - ## beamforming 4x4 matrix: - #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; - sdr_addrs = "addr=192.168.10.2,mgmt_addr=192.168.10.2,second_addr=192.168.20.2"; - clock_src = "external"; - } -); - -THREAD_STRUCT = ( - { - #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" - parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; - #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" - worker_config = "WORKER_ENABLE"; - } -); - - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - From 9aa7d1c88fd8bda4bc6827015ad14fae712b33d7 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 10:57:03 +0100 Subject: [PATCH 213/226] Remove redundant change of active bwp (it changes after RRC processing timer elapsed) --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 47 +++++-------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 109a588ed0..5af415eb7b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1983,49 +1983,28 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; - // TODO: To be improved the BWP selection - // For now, we are just changing to the first active BWP - - const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; - - const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; - const int bwp_id = servingCellConfig && servingCellConfig->firstActiveDownlinkBWP_Id ? - *servingCellConfig->firstActiveDownlinkBWP_Id : 0; - sched_ctrl->active_bwp = bwpList && bwp_id > 0 ? bwpList->list.array[bwp_id - 1] : NULL; - - const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; - const int ubwp_id = servingCellConfig && servingCellConfig->uplinkConfig && servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id ? - *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; - sched_ctrl->active_ubwp = ubwpList && ubwp_id > 0 ? ubwpList->list.array[ubwp_id - 1] : NULL; - - if(sched_ctrl->active_bwp) { - LOG_I(NR_MAC, "Changing to DL-BWP %i\n", bwp_id); - } - - if(sched_ctrl->active_ubwp) { - LOG_I(NR_MAC, "Changing to UL-BWP %i\n", ubwp_id); - } - // Pause scheduling according to: - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, - sib1); - // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - uint32_t delay_ms = bwpList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; + const NR_COMMON_channels_t *common_channels = &RC.nrmac[module_id]->common_channels[0]; + const NR_SIB1_t *sib1 = common_channels->sib1 ? common_channels->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; + NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, + common_channels->ServingCellConfigCommon, + sib1); + uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? + NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; + sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); - } - else { + LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %d with %d ms\n", frame, slot, UE_id, delay_ms); + } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); } nr_clear_ra_proc(module_id, CC_id, frame, ra); - if(sched_ctrl->retrans_dl_harq.head >= 0) { + if (sched_ctrl->retrans_dl_harq.head >= 0) { remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); } - } - else { + } else { LOG_D(NR_MAC, "(ue %i, rnti 0x%04x) Received Nack of RA-Msg4. Preparing retransmission!\n", UE_id, ra->rnti); ra->Msg4_frame = (frame + 1) % 1024; ra->Msg4_slot = 1; From af377945c3229caeb1dc7cf2270db10430ed674f Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 13:12:45 +0100 Subject: [PATCH 214/226] Fix hardcoded coreset and assignment from wrong array position --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 17 +++++++++++------ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 1 + .../LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 3 +++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 1 + .../NR_MAC_gNB/gNB_scheduler_primitives.c | 3 ++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 11 +++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 1 + openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + 10 files changed, 28 insertions(+), 19 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index c307b8235a..b62fdb5cf6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2598,6 +2598,7 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, nr_rnti_type_t rnti_type, uint16_t N_RB, int bwp_id, + NR_ControlResourceSetId_t coreset_id, uint16_t cset0_bwp_size) { uint16_t size = 0; @@ -2648,7 +2649,7 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, /// fixed: Format identifier 1, Hop flag 1, MCS 5, NDI 1, RV 2, HARQ PID 4, PUSCH TPC 2 Time Domain assgnmt 4 --20 size += 20; size += (uint8_t)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); // Freq domain assignment -- hopping scenario to be updated - int dci_10_size = nr_dci_size(initialDownlinkBWP,initialUplinkBWP,cg,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id, cset0_bwp_size); + int dci_10_size = nr_dci_size(initialDownlinkBWP,initialUplinkBWP,cg,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id, coreset_id, cset0_bwp_size); AssertFatal(dci_10_size >= size, "NR_UL_DCI_FORMAT_0_0 size is bigger than NR_DL_DCI_FORMAT_1_0! 3GPP TS 38.212 Section 7.3.1.0: DCI size alignment is not fully implemented"); size += dci_10_size - size; // Padding to match 1_0 size // UL/SUL indicator assumed to be 0 @@ -2992,11 +2993,15 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, size += dci_pdu->antenna_ports.nbits; LOG_D(NR_MAC,"dci_pdu->antenna_ports.nbits %d\n",dci_pdu->antenna_ports.nbits); // Tx Config Indication - int corset_id = 1 ; - long *isTciEnable = pdcch_Config->controlResourceSetToAddModList->list.array[corset_id-1]->tci_PresentInDCI; - if (isTciEnable != NULL) { - dci_pdu->transmission_configuration_indication.nbits = 3; - size += dci_pdu->transmission_configuration_indication.nbits; + for (int i = 0; i < pdcch_Config->controlResourceSetToAddModList->list.count; i++) { + if (pdcch_Config->controlResourceSetToAddModList->list.array[i]->controlResourceSetId == coreset_id) { + long *isTciEnable = pdcch_Config->controlResourceSetToAddModList->list.array[i]->tci_PresentInDCI; + if (isTciEnable != NULL) { + dci_pdu->transmission_configuration_indication.nbits = 3; + size += dci_pdu->transmission_configuration_indication.nbits; + } + break; + } } // SRS request if (cg->spCellConfig->spCellConfigDedicated->supplementaryUplink==NULL) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index d1becd41f9..2c39929413 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -55,6 +55,7 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDLBWP, nr_rnti_type_t rnti_type, uint16_t N_RB, int bwp_id, + NR_ControlResourceSetId_t coreset_id, uint16_t cset0_bwp_size); void find_aggregation_candidates(uint8_t *aggregation_level, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index fce6efa103..0dfbbf2be3 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -169,7 +169,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->SubcarrierSpacing = bwp_Common->genericParameters.subcarrierSpacing; } for (int i = 0; i < rel15->num_dci_options; i++) { - rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_C, rel15->BWPSize, dl_bwp_id, mac->type0_PDCCH_CSS_config.num_rbs); + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_C, rel15->BWPSize, dl_bwp_id, coreset_id, mac->type0_PDCCH_CSS_config.num_rbs); } break; case NR_RNTI_RA: @@ -185,7 +185,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->BWPStart = NRRIV2PRBOFFSET(bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } rel15->SubcarrierSpacing = initialDownlinkBWP->genericParameters.subcarrierSpacing; - rel15->dci_length_options[0] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[0]], rel15->dci_format_options[0], NR_RNTI_RA, rel15->BWPSize, dl_bwp_id, mac->type0_PDCCH_CSS_config.num_rbs); + rel15->dci_length_options[0] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[0]], rel15->dci_format_options[0], NR_RNTI_RA, rel15->BWPSize, dl_bwp_id, coreset_id, mac->type0_PDCCH_CSS_config.num_rbs); break; case NR_RNTI_P: break; @@ -200,7 +200,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->BWPStart = mac->type0_PDCCH_CSS_config.cset_start_rb; rel15->SubcarrierSpacing = initialDownlinkBWP->genericParameters.subcarrierSpacing; for (int i = 0; i < rel15->num_dci_options; i++) { - rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_TC, rel15->BWPSize, dl_bwp_id, mac->type0_PDCCH_CSS_config.num_rbs); + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_TC, rel15->BWPSize, dl_bwp_id, coreset_id, mac->type0_PDCCH_CSS_config.num_rbs); } break; case NR_RNTI_SP_CSI: @@ -223,7 +223,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon + 2; for (int i = 0; i < rel15->num_dci_options; i++) { - rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_SI, rel15->BWPSize, 0, mac->type0_PDCCH_CSS_config.num_rbs); + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_SI, rel15->BWPSize, 0, coreset_id, mac->type0_PDCCH_CSS_config.num_rbs); } break; case NR_RNTI_SFI: diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 5af415eb7b..9ac9f0d880 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -904,6 +904,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_RNTI_TC, pusch_pdu->bwp_size, ra->ul_bwp_id, + coresetid, nr_mac->cset0_bwp_size); // Mark the corresponding RBs as used @@ -1484,6 +1485,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_RNTI_RA, BWPSize, bwpid, + coresetid, nr_mac->cset0_bwp_size); // DL TX request @@ -1893,6 +1895,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, bwpid, + coresetid, nr_mac->cset0_bwp_size); // Add padding header and zero rest out if there is space left diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index b4ba1063f1..e2ceadb889 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -552,6 +552,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, rnti_type, pdsch_pdu_rel15->BWPSize, 0, + 0, gNB_mac->cset0_bwp_size); LOG_D(MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 68725f9544..1bf245010a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1374,6 +1374,7 @@ void nr_schedule_ue_spec(module_id_t module_id, rnti_type, pdsch_pdu->BWPSize, bwp ? bwp->bwp_Id : 0, + coresetid, gNB_mac->cset0_bwp_size); LOG_D(NR_MAC, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 0f1cd2949b..a88d65ab0f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1486,12 +1486,13 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, int rnti_type, int N_RB, int bwp_id, + NR_ControlResourceSetId_t coreset_id, uint16_t cset0_bwp_size) { uint8_t fsize = 0, pos = 0; uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload; *dci_pdu=0; - int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP,scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id, cset0_bwp_size); + int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP,scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id, coreset_id, cset0_bwp_size); pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 2897a86c31..c6e7db8f07 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -876,9 +876,7 @@ int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, int Mod_idP, int UE_i NR_TCI_State_t *tci =NULL; NR_TCI_StateId_t *tci_id = NULL; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; - NR_BWP_Downlink_t *bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; - NR_ControlResourceSet_t *coreset = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; int i; int flag = 0; int tci_stateID = -1; @@ -948,7 +946,6 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; - NR_BWP_Downlink_t *bwp = bwp_id > 0 ? sched_ctrl->active_bwp : NULL; //bwp indicator int n_dl_bwp=0; @@ -1078,10 +1075,8 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { } } - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = bwp ? - bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI : - CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[0]->tci_PresentInDCI; - + sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = sched_ctrl->coreset ? + sched_ctrl->coreset->tci_PresentInDCI : NULL; //filling pdsch tci state activation deactivation mac ce structure fields if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 488995d2bc..44cbe2ce9d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1938,6 +1938,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) rnti_types[0], pusch_pdu->bwp_size, bwp_id, + coresetid, nr_mac->cset0_bwp_size); memset(sched_pusch, 0, sizeof(*sched_pusch)); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 221ea878cb..da21f9e51f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -307,6 +307,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, int rnti_types, int N_RB, int bwp_id, + NR_ControlResourceSetId_t coreset_id, uint16_t cset0_bwp_size); void prepare_dci(const NR_CellGroupConfig_t *CellGroup, From 7d1f693ba1f722d3b04ace0703d516fe56c90967 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 13:28:18 +0100 Subject: [PATCH 215/226] Revert rbSize validation with target_dl_bw to previous version --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 2e76a2032a..c745c1921c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -303,7 +303,7 @@ void nr_preprocessor_phytest(module_id_t module_id, rbSize < target_dl_bw) rbSize++; /* found target_dl_bw? */ - if (rbStart+rbSize == target_dl_bw) + if (rbSize == target_dl_bw) break; /* at end and below target_dl_bw? */ if (rbStart + rbSize >= bwpSize) From 9f51b3f8b167b8d39aa2ef5850bc0cd5f133ced2 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 14:42:47 +0100 Subject: [PATCH 216/226] Harmonize and reuse the nr_rrc_config_dl_tda function to prepare PDSCH-TimeDomainResourceAllocation list --- openair2/GNB_APP/gnb_config.c | 6 ++++-- openair2/RRC/NR/MESSAGES/asn1_msg.c | 16 ++++------------ openair2/RRC/NR/nr_rrc_config.c | 19 +++++++++++++------ openair2/RRC/NR/nr_rrc_config.h | 4 +++- openair2/RRC/NR/rrc_gNB_reconfig.c | 16 ++++------------ 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index bd3c3b8d2c..6e817aab8c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -343,8 +343,10 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) { if (*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder!=0) scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = NULL; - // prepare DL Allocation lists - nr_rrc_config_dl_tda(scc); + // Prepare PDSCH-TimeDomainResourceAllocation list + nr_rrc_config_dl_tda(scc, + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList, + scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth); frame_type_t frame_type = get_frame_type((int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); if (frame_type == FDD) { diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index fabe00b832..7e38cac8a0 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1142,18 +1142,10 @@ void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp, bwp->bwp_Common->pdsch_ConfigCommon->choice.setup = calloc(1,sizeof(*bwp->bwp_Common->pdsch_ConfigCommon->choice.setup)); bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList = calloc(1,sizeof(*bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList)); - // Copy PDSCH TimeDomainResourceAllocation from InitialBWP - NR_PDSCH_TimeDomainResourceAllocation_t *pdschi; - for (int i=0;idownlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count;i++) { - pdschi= calloc(1,sizeof(*pdschi)); - if(scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->k0){ - pdschi->k0 = calloc(1,sizeof(*pdschi->k0)); - *pdschi->k0 = *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->k0; - } - pdschi->mappingType = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->mappingType; - pdschi->startSymbolAndLength = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength; - ASN_SEQUENCE_ADD(&bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,pdschi); - } + // Prepare PDSCH-TimeDomainResourceAllocation list + nr_rrc_config_dl_tda(scc, + bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList, + curr_bwp); /// BWP dedicated configuration bwp->bwp_Dedicated=calloc(1,sizeof(*bwp->bwp_Dedicated)); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index ff52fdb1ad..ef95443a5d 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -311,30 +311,37 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, } } -void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc){ +void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc, + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, + int curr_bwp) { frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); - int curr_bwp = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + // coreset duration setting to be improved in the framework of RRC harmonization, potentially using a common function int len_coreset = 1; if (curr_bwp < 48) len_coreset = 2; + // setting default TDA for DL with struct NR_PDSCH_TimeDomainResourceAllocation *timedomainresourceallocation = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t)); + // k0: Slot offset between DCI and its scheduled PDSCH (see TS 38.214 clause 5.1.2.1) When the field is absent the UE applies the value 0. + //timedomainresourceallocation->k0 = calloc(1,sizeof(*timedomainresourceallocation->k0)); + //*timedomainresourceallocation->k0 = 0; timedomainresourceallocation->mappingType = NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; timedomainresourceallocation->startSymbolAndLength = get_SLIV(len_coreset,14-len_coreset); // basic slot configuration starting in symbol 1 til the end of the slot - ASN_SEQUENCE_ADD(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list, - timedomainresourceallocation); + ASN_SEQUENCE_ADD(&pdsch_TimeDomainAllocationList->list, timedomainresourceallocation); if(frame_type==TDD) { // TDD if(scc->tdd_UL_DL_ConfigurationCommon) { int dl_symb = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols; if(dl_symb > 1) { timedomainresourceallocation = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t)); + // k0: Slot offset between DCI and its scheduled PDSCH (see TS 38.214 clause 5.1.2.1) When the field is absent the UE applies the value 0. + //timedomainresourceallocation->k0 = calloc(1,sizeof(*timedomainresourceallocation->k0)); + //*timedomainresourceallocation->k0 = 0; timedomainresourceallocation->mappingType = NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; timedomainresourceallocation->startSymbolAndLength = get_SLIV(len_coreset,dl_symb-len_coreset); // mixed slot configuration starting in symbol 1 til the end of the dl allocation - ASN_SEQUENCE_ADD(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list, - timedomainresourceallocation); + ASN_SEQUENCE_ADD(&pdsch_TimeDomainAllocationList->list, timedomainresourceallocation); } } } diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 4bc9513bc5..ca6e20512e 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -111,7 +111,9 @@ typedef struct physicalcellgroup_s{ long RNTI_Value[MAX_NUM_CCs]; }physicalcellgroup_t; -void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc); +void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc, + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, + int curr_bwp); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 867662b396..7e453d486a 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -196,18 +196,10 @@ void fill_default_nsa_downlinkBWP(NR_BWP_Downlink_t *bwp, bwp->bwp_Common->pdsch_ConfigCommon->choice.setup = calloc(1,sizeof(*bwp->bwp_Common->pdsch_ConfigCommon->choice.setup)); bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList = calloc(1,sizeof(*bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList)); - // copy PDSCH TimeDomainResourceAllocation from InitialBWP - NR_PDSCH_TimeDomainResourceAllocation_t *pdschi; - for (int i=0;idownlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count;i++) { - pdschi= calloc(1,sizeof(*pdschi)); - if(servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->k0){ - pdschi->k0 = calloc(1,sizeof(*pdschi->k0)); - *pdschi->k0 = *servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->k0; - } - pdschi->mappingType = servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->mappingType; - pdschi->startSymbolAndLength = servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength; - ASN_SEQUENCE_ADD(&bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,pdschi); - } + // Prepare PDSCH-TimeDomainResourceAllocation list + nr_rrc_config_dl_tda(servingcellconfigcommon, + bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList, + curr_bwp); /// BWP dedicated configuration From 2f3ce42d3b6105770ae3c515ba6d69c5c66fc04f Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 17:04:09 +0100 Subject: [PATCH 217/226] Improve code readability in fix_scd function --- openair2/GNB_APP/gnb_config.c | 75 ++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 6e817aab8c..c11d6b8092 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -489,43 +489,44 @@ void fix_scd(NR_ServingCellConfig_t *scd) { // Check for DL PTRS parameters validity for (int bwp_i = 0 ; bwp_idownlinkBWP_ToAddModList->list.count; bwp_i++) { - if (scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS) { + NR_DMRS_DownlinkConfig_t *dmrs_dl_config = scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; + + if (dmrs_dl_config->phaseTrackingRS) { // If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.count - 1; i >= 0; i--) { - if ((*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1) - || (*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) { + for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.count - 1; i >= 0; i--) { + if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1) + || (*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) { LOG_I(GNB_APP, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); - free(scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS); - scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS = NULL; + free(dmrs_dl_config->phaseTrackingRS); + dmrs_dl_config->phaseTrackingRS = NULL; break; } } } - if (scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS) { + if (dmrs_dl_config->phaseTrackingRS) { // If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = - scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.count - 1; i >= 0; i--) { - if ((*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.array[i] < 0) - || (*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.array[i] > 29)) { + for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.count - 1; i >= 0; i--) { + if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] < 0) + || (*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] > 29)) { LOG_I(GNB_APP, "DL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i); - free(scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS); - scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS = NULL; + free(dmrs_dl_config->phaseTrackingRS); + dmrs_dl_config->phaseTrackingRS = NULL; break; } } } - if (scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS) { - if (*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->resourceElementOffset > 2) { + if (dmrs_dl_config->phaseTrackingRS) { + if (*dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset > 2) { LOG_I(GNB_APP, "Freeing DL PTRS resourceElementOffset \n"); - free(scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->resourceElementOffset); - scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->resourceElementOffset = NULL; + free(dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset); + dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset = NULL; } - if (*scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->epre_Ratio > 1) { + if (*dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio > 1) { LOG_I(GNB_APP, "Freeing DL PTRS epre_Ratio \n"); - free(scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->epre_Ratio); - scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->epre_Ratio = NULL; + free(dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio); + dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio = NULL; } } } @@ -533,38 +534,40 @@ void fix_scd(NR_ServingCellConfig_t *scd) { // Check for UL PTRS parameters validity for (int bwp_i = 0 ; bwp_iuplinkConfig->uplinkBWP_ToAddModList->list.count; bwp_i++) { - if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { + NR_DMRS_UplinkConfig_t *dmrs_ul_config = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; + + if (dmrs_ul_config->phaseTrackingRS) { // If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.count-1; i >= 0; i--) { - if ((*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] < 1) - || (*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] > 276)) { + for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.count-1; i >= 0; i--) { + if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] < 1) + || (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] > 276)) { LOG_I(GNB_APP, "UL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); - free(scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS); - scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS = NULL; + free(dmrs_ul_config->phaseTrackingRS); + dmrs_ul_config->phaseTrackingRS = NULL; break; } } } - if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { + if (dmrs_ul_config->phaseTrackingRS) { // If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.count-1; i >= 0; i--) { - if ((*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] < 0) - || (*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] > 29)) { + for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.count-1; i >= 0; i--) { + if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] < 0) + || (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] > 29)) { LOG_I(GNB_APP, "UL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i); - free(scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS); - scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS = NULL; + free(dmrs_ul_config->phaseTrackingRS); + dmrs_ul_config->phaseTrackingRS = NULL; break; } } } - if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) { + if (dmrs_ul_config->phaseTrackingRS) { // Check for UL PTRS parameters validity - if (*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset > 2) { + if (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset > 2) { LOG_I(GNB_APP, "Freeing UL PTRS resourceElementOffset \n"); - free(scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset); - scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset = NULL; + free(dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset); + dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset = NULL; } } From 54f49fd25344ea43177a2f3afdbe2f3997ba4fa9 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 12 May 2022 17:33:35 +0100 Subject: [PATCH 218/226] Remove duplicated code for bwp common validation --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 11 +---- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 2 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 43 ++++++++++++-------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index cc287872f1..b0d41f317b 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -508,16 +508,7 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd, NR_BWP_Id_t dl_bwp_id) { - - NR_BWP_DownlinkCommon_t *bwp_Common = NULL; - if(dl_bwp_id > 0 && scd->downlinkBWP_ToAddModList) { - bwp_Common = scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]->bwp_Common; - } else if(mac->scc) { - bwp_Common = mac->scc->downlinkConfigCommon->initialDownlinkBWP; - } else if(mac->scc_SIB) { - bwp_Common = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; - } - + NR_BWP_DownlinkCommon_t *bwp_Common = get_bwp_downlink_common(mac, dl_bwp_id); AssertFatal(bwp_Common != NULL, "bwp_Common is null\n"); NR_SetupRelease_PDCCH_ConfigCommon_t *pdcch_ConfigCommon = bwp_Common->pdcch_ConfigCommon; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 86d72becef..ccd8ed8305 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -260,6 +260,8 @@ void get_bwp_info(NR_UE_MAC_INST_t *mac, NR_BWP_UplinkDedicated_t **ubwpd, NR_BWP_UplinkCommon_t **ubwpc); +NR_BWP_DownlinkCommon_t *get_bwp_downlink_common(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t dl_bwp_id); + uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, uint8_t dci_format, uint8_t dci_length, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index ccb90aa22f..dca9e1db56 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -191,24 +191,19 @@ void get_bwp_info(NR_UE_MAC_INST_t *mac, NR_BWP_UplinkDedicated_t **ubwpd, NR_BWP_UplinkCommon_t **ubwpc) { - if (dl_bwp_id > 0) { - AssertFatal(mac->DLbwp[dl_bwp_id-1]!=NULL,"mac->DLbwp[%d] is null, shouldn't be\n", - (int)dl_bwp_id-1); - *bwpd = mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated; - if (mac->DLbwp[dl_bwp_id-1]->bwp_Common) *bwpc = mac->DLbwp[dl_bwp_id-1]->bwp_Common; - else if (mac->scc) *bwpc = mac->scc->downlinkConfigCommon->initialDownlinkBWP; - else if (mac->scc_SIB) *bwpc = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; - AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); - } else { - if (mac->cg && - mac->cg->spCellConfig && - mac->cg->spCellConfig->spCellConfigDedicated && - mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP) - *bwpd = mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; - if (mac->scc) *bwpc = mac->scc->downlinkConfigCommon->initialDownlinkBWP; - else if (mac->scc_SIB) *bwpc = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; - AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); - } + if (dl_bwp_id > 0) { + AssertFatal(mac->DLbwp[dl_bwp_id-1]!=NULL,"mac->DLbwp[%d] is null, shouldn't be\n", (int)dl_bwp_id-1); + *bwpd = mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated; + } else { + if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP) + *bwpd = mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + } + + *bwpc = get_bwp_downlink_common(mac, dl_bwp_id); + AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); if (ul_bwp_id > 0) { AssertFatal(mac->ULbwp[ul_bwp_id-1]!=NULL,"mac->ULbwp[%d] is null, shouldn't be\n", @@ -233,6 +228,18 @@ void get_bwp_info(NR_UE_MAC_INST_t *mac, } } +NR_BWP_DownlinkCommon_t *get_bwp_downlink_common(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t dl_bwp_id) { + NR_BWP_DownlinkCommon_t *bwp_Common = NULL; + if (dl_bwp_id > 0 && mac->cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { + bwp_Common = mac->cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[dl_bwp_id-1]->bwp_Common; + } else if (mac->scc) { + bwp_Common = mac->scc->downlinkConfigCommon->initialDownlinkBWP; + } else if (mac->scc_SIB) { + bwp_Common = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; + } + return bwp_Common; +} + NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon) { NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; From 09c3597b46e063d1d320ae9d6fdd2b2f198dfdee Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 May 2022 18:47:47 +0200 Subject: [PATCH 219/226] Only check T tracer if EPC has been defined --- ci-scripts/ran.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 97c5b9696e..680763d247 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -383,17 +383,19 @@ class RANManagement(): # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - localEpcIpAddr = EPC.IPAddress - localEpcUserName = EPC.UserName - localEpcPassword = EPC.Password - mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) - eth_interface = 'any' - fltr = 'sctp' - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') - self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' - mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) - mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) - mySSH.close() + if EPC.IPAddress != "none": + localEpcIpAddr = EPC.IPAddress + localEpcUserName = EPC.UserName + localEpcPassword = EPC.Password + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) + eth_interface = 'any' + fltr = 'sctp' + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') + self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' + mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) + mySSH.close() + mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath, '\$', 5) # Initialize_eNB_args usually start with -O and followed by the location in repository From a9dcdcbbcbbbadb7262d7db8e1217e0c00ee799d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 May 2022 20:54:02 +0200 Subject: [PATCH 220/226] Fix name of html module --- ci-scripts/cls_physim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/cls_physim.py b/ci-scripts/cls_physim.py index ecd8f63af1..0342333c06 100644 --- a/ci-scripts/cls_physim.py +++ b/ci-scripts/cls_physim.py @@ -168,7 +168,7 @@ class PhySim: mySSH.close() #check build status and update HTML object - lHTML = html.HTMLManagement() + lHTML = cls_oai_html.HTMLManagement() lHTML=self.__CheckBuild_PhySim(htmlObj,constObj) return lHTML @@ -186,6 +186,6 @@ class PhySim: mySSH.command(self.__workSpacePath+'ran_build/build/ldpctest ' + self.runargs + ' >> '+self.__runLogFile, '\$', 30) mySSH.close() #return updated HTML to main - lHTML = html.HTMLManagement() + lHTML = cls_oai_html.HTMLManagement() lHTML=self.__CheckResults_PhySim(htmlObj,constObj,testcase_id) return lHTML From 64f4d34c254d768d4103e50fb5cb0e442c2a51b9 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 12 May 2022 20:40:22 +0100 Subject: [PATCH 221/226] Fix tda in dlsim considering the new configuration for NSA in fill_default_nsa_downlinkBWP --- openair1/SIMULATION/NR_PHY/dlsim.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 5a4168624b..f007d64023 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -293,7 +293,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, UE_info->CellGroup[0], sched_ctrl->active_bwp, NULL, - /* tda = */ 2, + /* tda = */ 0, g_nrOfLayers, sched_ctrl, ps); @@ -315,8 +315,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, ps->N_PRB_DMRS * ps->N_DMRS_SLOT, 0 /* N_PRB_oh, 0 for initialBWP */, 0 /* tb_scaling */, - ps->nrOfLayers) - >> 3; + ps->nrOfLayers) >> 3; /* the simulator assumes the HARQ PID is equal to the slot number */ sched_pdsch->dl_harq_pid = slot; From 7c5a82bf1c671bbf95eb1beb7e3b1e74a2af9c82 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 May 2022 09:20:31 +0200 Subject: [PATCH 222/226] Format Hdashboard Gitlab post using Markdown --- ci-scripts/ran_dashboard/Hdashboard.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci-scripts/ran_dashboard/Hdashboard.py b/ci-scripts/ran_dashboard/Hdashboard.py index 1b65c7af4f..993d0dded8 100644 --- a/ci-scripts/ran_dashboard/Hdashboard.py +++ b/ci-scripts/ran_dashboard/Hdashboard.py @@ -528,15 +528,15 @@ class Dashboard: editable_mr = project.mergerequests.get(int(mr)) mr_notes = editable_mr.notes.list(all=True) - body = 'Consolidated Test Results
    '+\ - 'Tested CommitID: ' + commit + '
    ' + body = '[Consolidated Test Results](https://oaitestdashboard.s3.eu-west-1.amazonaws.com/MR'+mr+'/index.html)\\\n' + body += 'Tested CommitID: ' + commit + '\\\n' for i in range(0,n_tests): jobname = args[4*i] buildurl = args[4*i+1] buildid = args[4*i+2] status = args[4*i+3] - body += jobname+', status is '+status+', ('+buildid+')
    ' + body += jobname+': **'+status+'** ([' + buildid + '](' + buildurl + '))\\\n' #create new note mr_note = editable_mr.notes.create({ From 1c4bf402480f4e10415953cf134b83964e2e3081 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 13 May 2022 11:57:31 +0200 Subject: [PATCH 223/226] Fix caracal perf test: add option for N300, run only once (is consistent) --- ci-scripts/xml_files/gnb_phytest_usrp_run.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml index 5705533ab4..e7eb651d50 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml @@ -24,7 +24,7 @@ gNB-PHY-Test Run-gNB-PHY-Test tasks - 3 + 1 090101 000001 090109 @@ -33,7 +33,7 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test -q -U 787200 -T 106 -t 28 -D 130175 -m 28 -M 106 --log_config.global_log_options level,nocolor,time + -O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test -q -U 787200 -T 106 -t 28 -D 130175 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time NR 192.168.20.2 From 9b2fa3ca63531b8b842c1cb51333f0aa7f53059b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 13 May 2022 14:14:47 +0200 Subject: [PATCH 224/226] Increase PUSCH decoding defaults --- ci-scripts/datalog_rt_stats.default.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci-scripts/datalog_rt_stats.default.yaml b/ci-scripts/datalog_rt_stats.default.yaml index 02a90c86f4..0da04dcaed 100644 --- a/ci-scripts/datalog_rt_stats.default.yaml +++ b/ci-scripts/datalog_rt_stats.default.yaml @@ -15,7 +15,8 @@ Ref : DLSCH encoding : 230.0 L1 Rx processing : 175.0 PUSCH inner-receiver : 100.0 - PUSCH decoding : 180.0 + #PUSCH decoding : 180.0 + PUSCH decoding : 240.0 DL & UL scheduling timing stats : 37.0 UL Indication : 38.0 Threshold : From cc238a91e4e92966d619a40cb93828bbce832968 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 13 May 2022 15:13:21 +0100 Subject: [PATCH 225/226] Compute TDA startSymbolIndex and nrOfSymbols everytime function nr_set_pdsch_semi_static is called --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a88d65ab0f..eed9313757 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -603,23 +603,21 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, NR_PDSCH_Config_t *pdsch_Config = NULL; if (bwpd && bwpd->pdsch_Config) pdsch_Config = bwpd->pdsch_Config->choice.setup; LOG_D(NR_MAC,"tda %d, ps->time_domain_allocation %d,layers %d, ps->nrOfLayers %d, pdsch_config %p\n",tda,ps->time_domain_allocation,layers,ps->nrOfLayers,pdsch_Config); - if (ps->time_domain_allocation != tda) { - reset_dmrs = true; - ps->time_domain_allocation = tda; - NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = get_pdsch_TimeDomainAllocationList(bwp, scc, sib1); - AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); - ps->mapping_type = tdaList->list.array[tda]->mappingType; - if (pdsch_Config) { - if (ps->mapping_type == NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeB) - ps->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type == NULL ? 0 : 1; - else - ps->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1; - } + reset_dmrs = true; + ps->time_domain_allocation = tda; + NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = get_pdsch_TimeDomainAllocationList(bwp, scc, sib1); + AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); + ps->mapping_type = tdaList->list.array[tda]->mappingType; + if (pdsch_Config) { + if (ps->mapping_type == NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeB) + ps->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type == NULL ? 0 : 1; else - ps->dmrsConfigType = NFAPI_NR_DMRS_TYPE1; - const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; - SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); + ps->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1; } + else + ps->dmrsConfigType = NFAPI_NR_DMRS_TYPE1; + const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; + SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); const long f = ((bwp || bwpd) && sched_ctrl->search_space && From 6c43cdf4dcf6215c0ef19a81fb66105280289e9e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 16 May 2022 21:39:06 +0200 Subject: [PATCH 226/226] Hack to prevent segfault --- common/utils/ocp_itti/intertask_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 111a423dcb..43001ec95b 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -450,7 +450,7 @@ extern "C" { void itti_wait_tasks_end(void) { shutting_down = false; signal(SIGTERM, catch_sigterm); - signal(SIGINT, catch_sigterm); + //signal(SIGINT, catch_sigterm); while (! shutting_down) { sleep(24 * 3600);

    &7#;Zi<{%UbmkS_c2pl?SnDOV3ar*A!MTU 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®#FFXPBl-q2B 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 XJI&i2m|!?u8481QNlEEq^|<~6r_8hh literal 0 HcmV?d00001 diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png new file mode 100644 index 0000000000000000000000000000000000000000..c677b598e9894a1bbf0e1e7321497e4c51e6fb17 GIT binary patch literal 89436 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