diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index cd51f6a48f..1a5431bdd2 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -1972,49 +1972,6 @@ static const int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l[12][8] = { {0, 3072, -1, -1, 3, 1539, -1, -1}, // 14 // (DMRS l' position) }; -// TS 38.212 -static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; -static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, - 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55}; -static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59}; -static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61}; -static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25}; -static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32}; -static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33}; -static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35}; -static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22}; -static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29}; -static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15}; -static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6}; -static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8}; -static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3}; -static const uint16_t table_7_3_1_1_2_28[3][15] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; -static const uint16_t table_7_3_1_1_2_29[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0}, -}; -static const uint16_t table_7_3_1_1_2_30[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, -}; -static const uint16_t table_7_3_1_1_2_31[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, -}; -static const uint16_t table_7_3_1_1_2_32[3][15] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; - // the following tables contain 10 times the value reported in 214 (in line with SCF specification and to avoid fractional values) //Table 5.1.3.1-1 of 38.214 static const uint16_t Table_51311[32][2] = {{2, 1200}, {2, 1570}, {2, 1930}, {2, 2510}, {2, 3080}, {2, 3790}, {2, 4490}, {2, 5260}, @@ -2503,61 +2460,61 @@ static int binomial(int n, int k) return c; } +int srs_codebook_nb_res(NR_SRS_Config_t *srs_config) +{ + int count = 0; + for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) + count++; + } + return count; +} + +int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config) +{ + int count = 0; + for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) + count++; + } + return count; +} + +int srs_binomial_sum(int count, int Lmax) +{ + int lmin = 0; + int lsum = 0; + lmin = count < Lmax ? count : Lmax; + for (int k = 1; k <= lmin; k++) + lsum += binomial(count, k); + return lsum; +} + // #define DEBUG_SRS_RESOURCE_IND -uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, - NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - nr_srs_feedback_t *srs_feedback, - uint32_t *val) + +static uint8_t compute_srs_resource_indicator_size(long *maxMIMO_Layers, NR_PUSCH_Config_t *pusch_Config, NR_SRS_Config_t *srs_config) { uint8_t nbits = 0; - - // SRI occupies a number of bits which is dependent upon the uplink transmission scheme, and it is used to determine - // the antenna ports and uplink transmission beam to use for PUSCH transmission. In the case of codebook based - // transmission, the SRI is used to select between SRS Resources belonging to different antenna panels - // (kind of directional antenna). There can be up to 2 SRS Resources (2 antenna panels). In the case of non-codebook - // based transmission, the SRI is used to select one or more SRS Resources from a set of N_SRS resources. The number - // of SRS Resources selected corresponds to the number of layers (rank) to be transmitted. - if (val) { - *val = 0; - } - if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) { - if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) { - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_codebook\n"); #endif - // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook, // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook. - int count = 0; - for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) { - count++; - } - } - if (count>0) { + int count = srs_codebook_nb_res(srs_config); + if (count > 0) nbits = ceil(log2(count)); - if (val && srs_feedback && count > 1) { - *val = table_7_3_1_1_2_32[count-2][srs_feedback->sri]; - } - } - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); LOG_I(NR_MAC, "count = %i\n", count); #endif - } else { - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_nonCodebook\n"); #endif - // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k)))) // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter @@ -2572,68 +2529,29 @@ uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, if (maxMIMO_Layers != NULL) Lmax = *maxMIMO_Layers; else - AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); - int lmin = 0; - int lsum = 0; - int count = 0; - for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) { - count++; - } - } - lmin = count < Lmax ? count : Lmax; - for (int k=1;k<=lmin;k++) { - lsum += binomial(count,k); - } - if (lsum>0) { + AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + int count = srs_non_codebook_nb_res(srs_config); + int lsum = srs_binomial_sum(count, Lmax); + if (lsum > 0) nbits = ceil(log2(lsum)); - if (val && srs_feedback && nbits > 0) { - switch(Lmax) { - case 1: - *val = table_7_3_1_1_2_28[count-2][srs_feedback->sri]; - break; - case 2: - *val = table_7_3_1_1_2_29[count-2][srs_feedback->sri]; - break; - case 3: - *val = table_7_3_1_1_2_30[count-2][srs_feedback->sri]; - break; - case 4: - *val = table_7_3_1_1_2_31[count-2][srs_feedback->sri]; - break; - default: - LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax); - } - } - } - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); LOG_I(NR_MAC, "count = %i\n", count); LOG_I(NR_MAC, "Lmax = %i\n", Lmax); LOG_I(NR_MAC, "lsum = %i\n", lsum); #endif - } } - return nbits; } -uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - dci_field_t srs_resource_indicator, - nr_srs_feedback_t *srs_feedback, - const uint8_t *nrOfLayers, - int *tpmi, - uint32_t *val) +static uint8_t compute_precoding_info_size(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator) { // It is only applicable to codebook based transmission. This field occupies 0 bits for non-codebook based // transmission. It also occupies 0 bits for codebook based transmission using a single antenna port. uint8_t nbits = 0; - if (val) { - *val = 0; - } uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator); if (!pusch_Config @@ -2645,7 +2563,6 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, long max_rank = *pusch_Config->maxRank; long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; long *codebookSubset = pusch_Config->codebookSubset; - int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1; if (pusch_antenna_ports == 2) { @@ -2658,23 +2575,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, // of higher layer parameter codebookSubset; if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { nbits = 2; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 1; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } else { nbits = 3; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } } } else { @@ -2685,27 +2590,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent; if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { nbits = 2; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) || (*nrOfLayers==2 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2; - } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 2; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) || (*nrOfLayers==2 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? ul_tpmi : 2; - } } else { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) || (*nrOfLayers==2 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] : - table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi]; - } } } } @@ -2722,37 +2611,16 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 3; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 4; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = table_7_3_1_1_2_3A[ul_tpmi]; } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 2; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi); - } } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 5; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = ul_tpmi; } } } else { @@ -2769,99 +2637,26 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, if (max_rank == 2) { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi==13)) || (*nrOfLayers==2 && ul_tpmi <= 6), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 5; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = *nrOfLayers==1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi]; } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi == 13)) || (*nrOfLayers==2 && ul_tpmi <= 6) || - (*nrOfLayers==3 && ul_tpmi <= 1) || (*nrOfLayers==4 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 6; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13) || - (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - switch (*nrOfLayers) { - case 1: - *val = table_7_3_1_1_2_2B_1layer[ul_tpmi]; - break; - case 2: - *val = table_7_3_1_1_2_2B_2layers[ul_tpmi]; - break; - case 3: - *val = table_7_3_1_1_2_2B_3layers[ul_tpmi]; - break; - case 4: - *val = table_7_3_1_1_2_2B_4layers[ul_tpmi]; - break; - default: - LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); - } } } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 3) || (*nrOfLayers==2 && ul_tpmi <= 5) || - (*nrOfLayers==3 && ul_tpmi == 0) || (*nrOfLayers==4 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - } } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { nbits = 5; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 11) || (*nrOfLayers==2 && ul_tpmi <= 13) || - (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 6; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 28) || (*nrOfLayers==2 && ul_tpmi <= 22) || - (*nrOfLayers==3 && ul_tpmi <= 7) || (*nrOfLayers==4 && ul_tpmi <= 5), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - switch (*nrOfLayers) { - case 1: - *val = table_7_3_1_1_2_2_1layer[ul_tpmi]; - break; - case 2: - *val = table_7_3_1_1_2_2_2layers[ul_tpmi]; - break; - case 3: - *val = table_7_3_1_1_2_2_3layers[ul_tpmi]; - break; - case 4: - *val = table_7_3_1_1_2_2_4layers[ul_tpmi]; - break; - default: - LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); - } } } } - } return nbits; } @@ -3100,12 +2895,11 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, } // SRS resource indicator dci_pdu->srs_resource_indicator.nbits = - compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config, NULL, NULL); + compute_srs_resource_indicator_size(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config); size += dci_pdu->srs_resource_indicator.nbits; LOG_D(NR_MAC, "dci_pdu->srs_resource_indicator.nbits %d\n", dci_pdu->srs_resource_indicator.nbits); // Precoding info and number of layers - dci_pdu->precoding_information.nbits = - compute_precoding_information(pusch_Config, srs_config, dci_pdu->srs_resource_indicator, NULL, NULL, NULL, NULL); + dci_pdu->precoding_information.nbits = compute_precoding_info_size(pusch_Config, srs_config, dci_pdu->srs_resource_indicator); size += dci_pdu->precoding_information.nbits; LOG_D(NR_MAC, "dci_pdu->precoding_informaiton.nbits=%d\n", dci_pdu->precoding_information.nbits); // Antenna ports diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index ff6775df96..f76f54b158 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -41,6 +41,49 @@ #define NB_SRS_PERIOD (18) static const uint16_t srs_period[NB_SRS_PERIOD] = { 0, 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; +// TS 38.212 +static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; +static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, + 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55}; +static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59}; +static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61}; +static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25}; +static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32}; +static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33}; +static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35}; +static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22}; +static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29}; +static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15}; +static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6}; +static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8}; +static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3}; +static const uint16_t table_7_3_1_1_2_28[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; +static const uint16_t table_7_3_1_1_2_29[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0}, +}; +static const uint16_t table_7_3_1_1_2_30[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, +}; +static const uint16_t table_7_3_1_1_2_31[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, +}; +static const uint16_t table_7_3_1_1_2_32[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + typedef enum { pusch_dmrs_pos0 = 0, pusch_dmrs_pos1 = 1, @@ -81,20 +124,6 @@ void config_frame_structure(int mu, uint8_t frame_type, frame_structure_t *fs); -uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, - NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - nr_srs_feedback_t *srs_feedback, - uint32_t *val); - -uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - dci_field_t srs_resource_indicator, - nr_srs_feedback_t *srs_feedback, - const uint8_t *nrOfLayers, - int *tpmi, - uint32_t *val); - NR_PDSCH_TimeDomainResourceAllocationList_t *get_dl_tdalist(const NR_UE_DL_BWP_t *DL_BWP, int controlResourceSetId, int ss_type, @@ -197,7 +226,9 @@ uint32_t nr_get_code_rate_dl(uint8_t Imcs, uint8_t table_idx); /** \brief Computes Q based on I_MCS PDSCH and table_idx for uplink. Implements MCS Tables from 38.214. */ uint8_t nr_get_Qm_ul(uint8_t Imcs, uint8_t table_idx); uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx); - +int srs_binomial_sum(int count, int Lmax); +int srs_codebook_nb_res(NR_SRS_Config_t *srs_config); +int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config); uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset); void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int *offset); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 7e0f84e2fe..264150f314 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -895,6 +895,265 @@ dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac, return dci_payload; } +static uint32_t compute_srs_resource_indicator(long *maxMIMO_Layers, + NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + nr_srs_feedback_t *srs_feedback) +{ + uint32_t val = 0; + if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) { + if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) { + + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to + // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook, + // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer + // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook. + int count = srs_codebook_nb_res(srs_config); + if (count > 1) + val = table_7_3_1_1_2_32[count - 2][srs_feedback->sri]; + } else { + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k)))) + // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where + // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter + // srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value nonCodeBook and: + // + // - if UE supports operation with maxMIMO-Layers and the higher layer parameter maxMIMO-Layers of + // PUSCH-ServingCellConfig of the serving cell is configured, Lmax is given by that parameter; + // + // - otherwise, Lmax is given by the maximum number of layers for PUSCH supported by the UE for the serving cell + // for non-codebook based operation. + int Lmax = 0; + if (maxMIMO_Layers != NULL) + Lmax = *maxMIMO_Layers; + else + AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + int count = srs_non_codebook_nb_res(srs_config); + int lsum = srs_binomial_sum(count, Lmax); + if (lsum > 0 && ceil(log2(lsum)) > 0) { + switch(Lmax) { + case 1: + val = table_7_3_1_1_2_28[count-2][srs_feedback->sri]; + break; + case 2: + val = table_7_3_1_1_2_29[count-2][srs_feedback->sri]; + break; + case 3: + val = table_7_3_1_1_2_30[count-2][srs_feedback->sri]; + break; + case 4: + val = table_7_3_1_1_2_31[count-2][srs_feedback->sri]; + break; + default: + LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax); + } + } + } + } + return val; +} + +static uint32_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator, + nr_srs_feedback_t *srs_feedback, + const uint8_t *nrOfLayers, + int *tpmi) +{ + uint32_t val = 0; + + uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator); + if (!pusch_Config + || (pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) + || pusch_antenna_ports == 1) { + return val; + } + + long max_rank = *pusch_Config->maxRank; + long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; + long *codebookSubset = pusch_Config->codebookSubset; + int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1; + + if (pusch_antenna_ports == 2) { + + if (max_rank == 1) { + // - 1 or 3 bits according to Table 7.3.1.1.2-5 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-5A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } else { + AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } + } + } else { + // - 2 or 4 bits according to Table 7.3.1.1.2-4 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-4A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) + || (*nrOfLayers==2 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) + || (*nrOfLayers==2 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? ul_tpmi : 2; + } else { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) + || (*nrOfLayers==2 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] : + table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi]; + } + } + } + + } else if (pusch_antenna_ports == 4) { + + if (max_rank == 1) { + // - 2, 4, or 5 bits according to Table 7.3.1.1.2-3 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 3 or 4 bits according to Table 7.3.1.1.2-3A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi); + } else { + AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi); + } + val = table_7_3_1_1_2_3A[ul_tpmi]; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi); + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi); + } else { + AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi); + } + val = ul_tpmi; + } + } else { + // - 4, 5, or 6 bits according to Table 7.3.1.1.2-2 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 4 or 5 bits according to Table 7.3.1.1.2-2A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=2, transform precoder is disabled, and according to the values of higher layer parameter + // codebookSubset; + // - 4 or 6 bits according to Table 7.3.1.1.2-2B for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=3 or 4, transform precoder is disabled, and according to the values of higher layer + // parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (max_rank == 2) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers==1 + && (ul_tpmi <= 3 || ul_tpmi == 13)) + || (*nrOfLayers == 2 && ul_tpmi <= 6), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15) + || (*nrOfLayers == 2 && ul_tpmi <= 13), + "TPMI %d is invalid!\n", + ul_tpmi); + } + val = *nrOfLayers == 1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi]; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers == 1 + && (ul_tpmi <= 3 || ul_tpmi == 13)) + || (*nrOfLayers == 2 && ul_tpmi <= 6) + || (*nrOfLayers == 3 && ul_tpmi <= 1) + || (*nrOfLayers == 4 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15) + || (*nrOfLayers == 2 && ul_tpmi <= 13) + || (*nrOfLayers == 3 && ul_tpmi <= 2) + || (*nrOfLayers == 4 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + } + switch (*nrOfLayers) { + case 1: + val = table_7_3_1_1_2_2B_1layer[ul_tpmi]; + break; + case 2: + val = table_7_3_1_1_2_2B_2layers[ul_tpmi]; + break; + case 3: + val = table_7_3_1_1_2_2B_3layers[ul_tpmi]; + break; + case 4: + val = table_7_3_1_1_2_2B_4layers[ul_tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 3) + || (*nrOfLayers == 2 && ul_tpmi <= 5) + || (*nrOfLayers == 3 && ul_tpmi == 0) + || (*nrOfLayers == 4 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 11) + || (*nrOfLayers == 2 && ul_tpmi <= 13) + || (*nrOfLayers == 3 && ul_tpmi <= 2) + || (*nrOfLayers == 4 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 28) + || (*nrOfLayers == 2 && ul_tpmi <= 22) + || (*nrOfLayers == 3 && ul_tpmi <= 7) + || (*nrOfLayers == 4 && ul_tpmi <= 5), + "TPMI %d is invalid!\n", + ul_tpmi); + } + switch (*nrOfLayers) { + case 1: + val = table_7_3_1_1_2_2_1layer[ul_tpmi]; + break; + case 2: + val = table_7_3_1_1_2_2_2layers[ul_tpmi]; + break; + case 3: + val = table_7_3_1_1_2_2_3layers[ul_tpmi]; + break; + case 4: + val = table_7_3_1_1_2_2_4layers[ul_tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } + return val; +} + void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, @@ -940,23 +1199,20 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, // bwp indicator as per table 7.3.1.1.2-1 in 38.212 dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator - if (pusch_Config && - pusch_Config->txConfig != NULL) { + if (pusch_Config && pusch_Config->txConfig != NULL) { AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook, "Non Codebook configuration non supported\n"); - compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, - pusch_Config, - ul_bwp->srs_Config, - srs_feedback, - &dci_pdu_rel15->srs_resource_indicator.val); + dci_pdu_rel15->srs_resource_indicator.val = compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, + pusch_Config, + ul_bwp->srs_Config, + srs_feedback); } - compute_precoding_information(pusch_Config, - ul_bwp->srs_Config, - dci_pdu_rel15->srs_resource_indicator, - srs_feedback, - &pusch_pdu->nrOfLayers, - tpmi, - &dci_pdu_rel15->precoding_information.val); + dci_pdu_rel15->precoding_information.val = compute_precoding_information(pusch_Config, + ul_bwp->srs_Config, + dci_pdu_rel15->srs_resource_indicator, + srs_feedback, + &pusch_pdu->nrOfLayers, + tpmi); // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports