diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 596916f091..1da8710651 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -152,6 +152,8 @@ typedef struct { uint16_t E_uci_ACK; // number of coded HARQ-ACK bits uint16_t Q_dash_ACK_rvd; // number of coded HARQ-ACK symbols reserved uint16_t E_uci_ACK_rvd; // number of coded HARQ-ACK bits reserved + uint16_t Q_dash_CSI1; // number of coded CSI part 1 symbols + uint16_t E_uci_CSI1; // number of coded CSI part 1 bits uint32_t G_ulsch; // bit capacity of ULSCH } rate_match_info_uci_t; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 8251f278ad..6603dce02e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -517,6 +517,98 @@ static void map_symbols(const nr_phy_pxsch_params_t p, } } +// Function to lookup beta offset value from Table 9.3-2 in TS 38.213 +static double get_beta_offset_csi(const uint8_t beta_offset_idx) +{ + static const double beta_offset_values[19] = {1.125, + 1.250, + 1.375, + 1.625, + 1.750, + 2.000, + 2.250, + 2.500, + 2.875, + 3.125, + 3.500, + 4.000, + 5.000, + 6.250, + 8.000, + 10.000, + 12.625, + 15.875, + 20.000}; + + if (beta_offset_idx >= sizeofArray(beta_offset_values)) { + LOG_E(PHY, "Invalid beta_offset_index %d, using default value\n", beta_offset_idx); + return beta_offset_values[9]; + } + + return beta_offset_values[beta_offset_idx]; +} + +/* + * This function maps the CSI part 1 bits + */ +static void map_csi1(uci_on_pusch_bit_type_t *template, + const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + uint16_t G_csi1, + uint8_t l1_c, + const uint32_t *m_uci_current, + const uint32_t *m_ulsch_initial) +{ + const uint8_t n_symbols = pusch_pdu->nr_of_symbols; + const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; + + uint32_t symbol_start_bit_idx[14] = {0}; + for (uint8_t s = 1; s < n_symbols; s++) { + symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); + } + + uint32_t total_placed = 0; + for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_csi1; sym++) { + const uint32_t uci_re_on_sym = m_uci_current[sym]; + + if (uci_re_on_sym <= 0) { + continue; + } + + const uint32_t remaining_to_place = G_csi1 - total_placed; + uint32_t d_factor_re; + const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm); + + if (num_re_to_select >= uci_re_on_sym) { + d_factor_re = 1; + } else { + d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); + if (d_factor_re == 0) { + d_factor_re = 1; + } + } + + uint32_t re_offset = 0; + while (re_offset < uci_re_on_sym && total_placed < G_csi1) { + if (template[symbol_start_bit_idx[sym] + (re_offset * nlqm)] != BIT_TYPE_ULSCH) { + re_offset++; + continue; // if RE already allocated to UCI or reserved for ACK + } + for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { + if (total_placed >= G_csi1) { + break; + } + + uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; + uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; + template[cw_idx] = BIT_TYPE_CSI1; + + total_placed++; + } + re_offset += d_factor_re; + } + } +} + // Function to lookup beta offset value from Table 9.3-1 in TS 38.213 static double get_beta_offset_harq_ack(uint8_t beta_offset_index) { @@ -586,13 +678,19 @@ static int get_crc_uci(const uint16_t ouci) return L; } -static uint16_t get_Qd(const uint16_t oack, double beta, double alpha, const uint32_t sumKr, const uint32_t s1, const uint32_t s2) +static uint16_t get_Qd(const uint16_t oack, + double beta, + double alpha, + const uint32_t sumKr, + const uint32_t s1, + const uint32_t s2, + const uint32_t sub) { if (oack == 0) return 0; uint16_t first_term = ceil(((double)oack + get_crc_uci(oack)) * (double)beta * s1 / sumKr); - uint16_t second_term = ceil(alpha * s2); + uint16_t second_term = ceil(alpha * s2) - sub; return (first_term < second_term) ? first_term : second_term; } @@ -661,26 +759,34 @@ static rate_match_info_uci_t calc_rate_match_info_uci(const nfapi_nr_ue_pusch_pd rate_match_info_uci_t rminfo = {0}; // get the number of coded HARQ-ACK symbols and bits, TS 38.212 section 6.3.2.4.1.1 - rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2); + rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2, 0); rminfo.E_uci_ACK = rminfo.Q_dash_ACK * nlqm; if (oack_rvd > 0) { - rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2); + rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2, 0); rminfo.E_uci_ACK_rvd = rminfo.Q_dash_ACK_rvd * nlqm; } + // get beta offset for csi + const double beta_csi1 = get_beta_offset_csi(pusch_pdu->pusch_uci.beta_offset_csi1); + + // get the number of coded CSI part 1 symbols and bits, TS 38.212 section 6.3.2.4.1.2 + const uint16_t ocsi1 = pusch_pdu->pusch_uci.csi_part1_bit_length; + rminfo.Q_dash_CSI1 = get_Qd(ocsi1, beta_csi1, alpha, sumKr, s1, s1, rminfo.Q_dash_ACK); + rminfo.E_uci_CSI1 = rminfo.Q_dash_CSI1 * nlqm; + + rminfo.G_ulsch = *G - rminfo.E_uci_CSI1; if (oack_rvd == 0) { - rminfo.G_ulsch = *G - rminfo.E_uci_ACK; - } else { - rminfo.G_ulsch = *G; + rminfo.G_ulsch -= rminfo.E_uci_ACK; } *G = rminfo.G_ulsch; LOG_D(PHY, "[UCI_RATE_MATCH] sumKr=%u, s1=%u, s2=%u, Final G_ulsch (output G): %u\n", sumKr, s1, s2, *G); LOG_D(PHY, - "[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, G_ulsch=%u\n", + "[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, E_uci_CSI1=%u, G_ulsch=%u\n", rminfo.E_uci_ACK, rminfo.E_uci_ACK_rvd, + rminfo.E_uci_CSI1, rminfo.G_ulsch); return rminfo; @@ -909,11 +1015,14 @@ static void apply_template_to_codeword(uint8_t *codeword, uint32_t codeword_len, const uint8_t *ulsch_bits, const uint64_t *cack, + const uint64_t *csi1, uint16_t G_ack, + uint32_t G_csi1, uint32_t G_ulsch) { uint32_t ulsch_idx = 0; uint32_t ack_idx = 0; + uint32_t csi1_idx = 0; for (uint32_t i = 0; i < codeword_len; i++) { switch (template[i]) { @@ -935,6 +1044,15 @@ static void apply_template_to_codeword(uint8_t *codeword, } break; + case BIT_TYPE_CSI1: + if (G_csi1 > 0 && csi1_idx < G_csi1) { + uint32_t word_idx = csi1_idx / 64; + uint32_t bit_in_word_idx = csi1_idx % 64; + codeword[i] = (csi1[word_idx] >> bit_in_word_idx) & 1; + csi1_idx++; + } + break; + case BIT_TYPE_ACK_RESERVED: case BIT_TYPE_ULSCH: default: @@ -957,10 +1075,12 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_ unsigned int G_ulsch, uint16_t G_ack, uint32_t G_ack_rvd, + uint32_t G_csi1, uint8_t *codeword, uint32_t codeword_len, const uint8_t *ulsch_bits, - const uint64_t *cack) + const uint64_t *cack, + const uint64_t *csi1) { if (!pusch_pdu || !codeword || codeword_len == 0 || !template) return NULL; @@ -1002,11 +1122,13 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_ map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial); } + map_csi1(template, pusch_pdu, G_csi1, first_non_dmrs_sym, m_uci_current, m_ulsch_initial); + if (G_ack > 0 && G_ack_rvd > 0) { map_overlapped_ack(template, G_ack, l1_c, n_symbols, positions_by_sym, count_by_sym); } - apply_template_to_codeword(codeword, template, codeword_len, ulsch_bits, cack, G_ack, G_ulsch); + apply_template_to_codeword(codeword, template, codeword_len, ulsch_bits, cack, csi1, G_ack, G_csi1, G_ulsch); return template; } @@ -1106,7 +1228,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, return; } - if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) { + bool uci_present = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) || (pusch_pdu->pusch_uci.csi_part1_bit_length != 0); + if (uci_present) { rm_info = calc_rate_match_info_uci(pusch_pdu, harq_process_ul_ue, nl_qm, &G[pusch_id]); } @@ -1123,12 +1246,10 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig - if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) { - LOG_D(PHY, "[UCI_ON_PUSCH] Original HARQ-ACK bit length: %u\n", pusch_pdu->pusch_uci.harq_ack_bit_length); - LOG_D(PHY, "[UCI_ON_PUSCH] Initial G: %u\n", G_initial_total_pusch_bits); - // b is the block of bits transmitted on the physical channel after payload coding - uint64_t b[16] = {0}; // limit to 1024-bit encoded length + // b is the block of bits transmitted on the physical channel after payload coding + uint64_t b_ack[16] = {0}; // limit to 1024-bit encoded length + if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) { if (pucch_pdu == NULL) { LOG_E(PHY, "nr_ue_ulsch_procedures: pucch_pdu is NULL but HARQ-ACK is present. Cannot proceed with UCI encoding.\n"); stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); @@ -1141,7 +1262,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, true, rm_info.E_uci_ACK, mod_order, - &b[0]); + &b_ack[0]); LOG_D(PHY, "[UCI_ON_PUSCH] G_ulsch=%u (updated G[pusch_id]), G_ack=%u (M_bit), G_ack_rvd=%u, total_len=%u " @@ -1150,7 +1271,23 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, rm_info.E_uci_ACK, rm_info.E_uci_ACK_rvd, G_initial_total_pusch_bits); + uci_present |= true; + } + uint64_t b_csi1[16] = {0}; // limit to 1024-bit encoded length + if (pusch_pdu->pusch_uci.csi_part1_bit_length != 0) { + nr_uci_encoding(pusch_pdu->pusch_uci.csi_part1_payload, + pusch_pdu->pusch_uci.csi_part1_bit_length, + pucch_pdu->prb_size, + true, + rm_info.E_uci_CSI1, + mod_order, + &b_csi1[0]); + + uci_present |= true; + } + + if (uci_present) { uint8_t temp_codeword[G_initial_total_pusch_bits]; start_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING); nr_data_control_mapping(pusch_pdu, @@ -1158,18 +1295,17 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, G[pusch_id], rm_info.E_uci_ACK, rm_info.E_uci_ACK_rvd, + rm_info.E_uci_CSI1, temp_codeword, G_initial_total_pusch_bits, harq_process_ul_ue->f, - b); + b_ack, + b_csi1); stop_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING); memcpy(harq_process_ul_ue->f, temp_codeword, G_initial_total_pusch_bits); uci_mapping_template = template_buffer; } - AssertFatal(pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0, - "UCI (CSI) on PUSCH not supported at PHY\n"); - uint16_t start_rb = pusch_pdu->rb_start; uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB; @@ -1202,7 +1338,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH scrambling///////////////////////// uint32_t available_bits; - bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0); + bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0 || pusch_pdu->pusch_uci.csi_part1_bit_length != 0); if (is_uci_on_pusch) { // UCI on PUSCH is present, so available bits are the total codeword length