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 4c99da4e35..481f704da1 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 @@ -260,6 +260,13 @@ typedef struct } nfapi_nr_ue_pusch_data_t; +typedef struct csi_payload { + uint64_t part1_payload; + uint64_t part2_payload; + int p1_bits; + int p2_bits; +} nfapi_nr_ue_csi_payload_t; + typedef struct { // payloads with fixed array size @@ -267,10 +274,7 @@ typedef struct // vector without L1 implementation uint16_t harq_ack_bit_length; uint64_t harq_payload; - uint16_t csi_part1_bit_length; - uint64_t csi_part1_payload; - uint16_t csi_part2_bit_length; - uint64_t csi_part2_payload; + nfapi_nr_ue_csi_payload_t csi_payload; uint8_t alpha_scaling; // 0 = 0.5, 1 = 0.65, 2 = 0.8, 3 = 1 uint8_t beta_offset_harq_ack; uint8_t beta_offset_csi1; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 596916f091..fd7509e496 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -152,6 +152,10 @@ 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 + uint16_t Q_dash_CSI2; // number of coded CSI part 2 symbols + uint16_t E_uci_CSI2; // number of coded CSI part 2 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..6708cef338 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -517,6 +517,51 @@ 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]; +} + +static uint32_t get_d_factor_re(const uint32_t a, const uint32_t b) +{ + uint32_t d_factor_re; + if (a >= b) { + d_factor_re = 1; + } else { + d_factor_re = floor((double)b / a); + if (d_factor_re == 0) { + d_factor_re = 1; + } + } + return 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 +631,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 +712,41 @@ 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_payload.p1_bits; + 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; + + // get the number of coded CSI part 2 symbols and bits, TS 38.212 section 6.3.2.4.1.3 + const double beta_csi2 = get_beta_offset_csi(pusch_pdu->pusch_uci.beta_offset_csi2); + const uint16_t ocsi2 = pusch_pdu->pusch_uci.csi_payload.p2_bits; + rminfo.Q_dash_CSI2 = get_Qd(ocsi2, beta_csi2, alpha, sumKr, s1, s1, rminfo.Q_dash_ACK + rminfo.Q_dash_CSI1); + rminfo.E_uci_CSI2 = rminfo.Q_dash_CSI2 * nlqm; + + rminfo.G_ulsch = *G - (rminfo.E_uci_CSI1 + rminfo.E_uci_CSI2); 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, E_uci_CSI2=%u, G_ulsch=%u\n", rminfo.E_uci_ACK, rminfo.E_uci_ACK_rvd, + rminfo.E_uci_CSI1, + rminfo.E_uci_CSI2, rminfo.G_ulsch); return rminfo; @@ -747,115 +813,93 @@ static void get_first_uci_symbol(const uint8_t start_symbol, *dmrs_p1 -= start_symbol; } -/* - * This function builds the initial template by reserving positions for HARQ-ACK. - */ -static void build_template_reserve_ack(uci_on_pusch_bit_type_t *template, - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint32_t G_ack_rvd, - uint8_t l1_c, - const uint32_t *m_uci_current, - const uint32_t *m_ulsch_initial, - uint32_t positions_by_sym[][MAX_UCI_CODED_BITS], - uint32_t *count_by_sym) +static inline bool skip_mapping_current_uci(const uci_on_pusch_bit_type_t template, const uci_on_pusch_bit_type_t uci_type_to_map) { - const uint8_t n_symbols = pusch_pdu->nr_of_symbols; - const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; + bool ret = false; + switch (uci_type_to_map) { + case BIT_TYPE_ACK_RESERVED: + case BIT_TYPE_ACK: + // ACK bits get the highest priority. Don't skip + ret = false; + break; - memset(count_by_sym, 0, n_symbols * sizeof(uint32_t)); + case BIT_TYPE_CSI1: + // Skip if already occupied by ACK and reserved ACK. Template is initialized with ULSCH + ret = (template != BIT_TYPE_ULSCH); + break; - 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); - } + case BIT_TYPE_CSI2: + // Skip if already occupied by ACK but not reserved ACK + ret = (template != BIT_TYPE_ACK_RESERVED && template != BIT_TYPE_ULSCH); + break; - // Reserve Positions using RE-level D-Factor Distribution - uint32_t total_reserved = 0; - - for (uint8_t sym = l1_c; sym < n_symbols && total_reserved < G_ack_rvd; sym++) { - const uint32_t uci_re_on_sym = m_uci_current[sym]; - - if (uci_re_on_sym > 0) { - const uint32_t remaining_to_reserve = G_ack_rvd - total_reserved; - uint32_t d_factor_re; - const uint32_t num_re_to_select = ceil((double)remaining_to_reserve / 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; - } - } - - for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_reserved < G_ack_rvd; re_offset += d_factor_re) { - for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { - if (total_reserved >= G_ack_rvd) { - 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_ACK_RESERVED; - positions_by_sym[sym][count_by_sym[sym]] = cw_idx; - count_by_sym[sym]++; - - total_reserved++; - } - } - } + default: + AssertFatal(0, "Mapping called with incorrect UCI type\n"); } + return ret; } -/* - * This function maps the HARQ-ACK bits when O_ACK > 2 - */ -static void map_non_overlapped_ack(uci_on_pusch_bit_type_t *template, - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint16_t G_ack, - 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; +struct map_uci_common_arg { + uci_on_pusch_bit_type_t *template; + uci_on_pusch_bit_type_t uci_type_to_map; + uint32_t n_symbols; + uint32_t nlqm; + uint16_t G_uci; + uint8_t l1_c; + uint32_t *m_uci_current; + uint32_t *m_ulsch_initial; + uint32_t (*resv_ack_pos_symb)[MAX_UCI_CODED_BITS]; + uint32_t *resv_ack_count_symb; +}; - 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); +static void map_uci_common(struct map_uci_common_arg p) +{ + DevAssert((p.resv_ack_count_symb && p.resv_ack_pos_symb && (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED)) + || (!p.resv_ack_count_symb && !p.resv_ack_pos_symb && (p.uci_type_to_map != BIT_TYPE_ACK_RESERVED))); + + uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {0}; + for (uint8_t s = 1; s < p.n_symbols; s++) { + symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (p.m_ulsch_initial[s - 1] * p.nlqm); } + if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED) + memset(p.resv_ack_count_symb, 0, sizeof(*p.resv_ack_count_symb) * NR_SYMBOLS_PER_SLOT); + uint32_t total_placed = 0; - for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_ack; sym++) { - const uint32_t uci_re_on_sym = m_uci_current[sym]; + for (uint8_t sym = p.l1_c; sym < p.n_symbols && total_placed < p.G_uci; sym++) { + const uint32_t uci_re_on_sym = p.m_uci_current[sym]; - if (uci_re_on_sym > 0) { - const uint32_t remaining_to_place = G_ack - total_placed; - uint32_t d_factor_re; - const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm); + if (uci_re_on_sym <= 0) { + continue; + } - 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; - } + const uint32_t remaining_to_place = p.G_uci - total_placed; + const uint32_t num_re_to_select = ceil((double)remaining_to_place / p.nlqm); + + uint32_t d_factor_re = get_d_factor_re(num_re_to_select, uci_re_on_sym); + uint32_t re_offset = 0; + uint32_t *cur_sym_resv_ack_pos = p.resv_ack_pos_symb[sym]; + while (re_offset < uci_re_on_sym && total_placed < p.G_uci) { + uci_on_pusch_bit_type_t cur_template = p.template[symbol_start_bit_idx[sym] + (re_offset * p.nlqm)]; + if (skip_mapping_current_uci(cur_template, p.uci_type_to_map)) { + re_offset++; + continue; // if RE already allocated to UCI or reserved for ACK } - - for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_placed < G_ack; re_offset += d_factor_re) { - for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { - if (total_placed >= G_ack) { - 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_ACK; - - total_placed++; + for (uint32_t bit_in_re = 0; bit_in_re < p.nlqm; bit_in_re++) { + if (total_placed >= p.G_uci) { + break; } + + uint32_t bit_offset_in_sym = (re_offset * p.nlqm) + bit_in_re; + uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; + p.template[cw_idx] = p.uci_type_to_map; + if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED) { + cur_sym_resv_ack_pos[p.resv_ack_count_symb[sym]++] = cw_idx; + } + + total_placed++; } + re_offset += d_factor_re; } } } @@ -877,21 +921,13 @@ static void map_overlapped_ack(uci_on_pusch_bit_type_t *template, if (num_reserved_bits_on_sym > 0) { const uint32_t num_ack_remaining = G_ack - ack_bits_marked; - uint32_t d_factor; // This d-factor is calculated for stepping through the list of *reserved bits*. - if (num_ack_remaining >= num_reserved_bits_on_sym) { - d_factor = 1; - } else { - d_factor = floor((double)num_reserved_bits_on_sym / num_ack_remaining); - if (d_factor == 0) { - d_factor = 1; - } - } + const uint32_t d_factor_re = get_d_factor_re(num_ack_remaining, num_reserved_bits_on_sym); const uint32_t *reserved_indices_on_this_sym = positions_by_sym[sym_iter]; - for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor) { + for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor_re) { uint32_t pos_to_mark = reserved_indices_on_this_sym[i]; template[pos_to_mark] = BIT_TYPE_ACK_ULSCH; @@ -909,11 +945,17 @@ 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, + const uint64_t *csi2, uint16_t G_ack, + uint32_t G_csi1, + uint32_t G_csi2, uint32_t G_ulsch) { uint32_t ulsch_idx = 0; uint32_t ack_idx = 0; + uint32_t csi1_idx = 0; + uint32_t csi2_idx = 0; for (uint32_t i = 0; i < codeword_len; i++) { switch (template[i]) { @@ -935,6 +977,24 @@ 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_CSI2: + if (G_csi2 > 0 && csi2_idx < G_csi2) { + uint32_t word_idx = csi2_idx / 64; + uint32_t bit_in_word_idx = csi2_idx % 64; + codeword[i] = (csi2[word_idx] >> bit_in_word_idx) & 1; + csi2_idx++; + } + break; + case BIT_TYPE_ACK_RESERVED: case BIT_TYPE_ULSCH: default: @@ -957,10 +1017,14 @@ 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, + uint32_t G_csi2, uint8_t *codeword, uint32_t codeword_len, const uint8_t *ulsch_bits, - const uint64_t *cack) + const uint64_t *cack, + const uint64_t *csi1, + const uint64_t *csi2) { if (!pusch_pdu || !codeword || codeword_len == 0 || !template) return NULL; @@ -989,24 +1053,40 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_ uint32_t positions_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT][MAX_UCI_CODED_BITS] = {0}; uint32_t count_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; + struct map_uci_common_arg map_arg = {.template = template, + .n_symbols = pusch_pdu->nr_of_symbols, + .nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers, + .l1_c = l1_c, + .m_uci_current = m_uci_current, + .m_ulsch_initial = m_ulsch_initial}; if (G_ack_rvd > 0) { - build_template_reserve_ack(template, - pusch_pdu, - G_ack_rvd, - l1_c, - m_uci_current, - m_ulsch_initial, - positions_by_sym, - count_by_sym); + map_arg.uci_type_to_map = BIT_TYPE_ACK_RESERVED; + map_arg.G_uci = G_ack_rvd; + map_arg.resv_ack_pos_symb = positions_by_sym; + map_arg.resv_ack_count_symb = count_by_sym; + map_uci_common(map_arg); } else if (G_ack > 0) { - map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial); + map_arg.uci_type_to_map = BIT_TYPE_ACK; + map_arg.G_uci = G_ack; + map_uci_common(map_arg); } + // CSI part 1 + map_arg.uci_type_to_map = BIT_TYPE_CSI1; + map_arg.G_uci = G_csi1; + map_arg.resv_ack_pos_symb = NULL; + map_arg.resv_ack_count_symb = NULL; + map_uci_common(map_arg); + // CSI part 2 + map_arg.uci_type_to_map = BIT_TYPE_CSI2; + map_arg.G_uci = G_csi2; + map_uci_common(map_arg); + 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, csi2, G_ack, G_csi1, G_csi2, G_ulsch); return template; } @@ -1106,7 +1186,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_payload.p1_bits != 0); + if (uci_present) { rm_info = calc_rate_match_info_uci(pusch_pdu, harq_process_ul_ue, nl_qm, &G[pusch_id]); } @@ -1123,12 +1204,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 +1220,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 +1229,31 @@ 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); + } + uint64_t b_csi1[16] = {0}; // limit to 1024-bit encoded length + uint64_t b_csi2[16] = {0}; // limit to 1024-bit encoded length + if (pusch_pdu->pusch_uci.csi_payload.p1_bits != 0) { + nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part1_payload, + pusch_pdu->pusch_uci.csi_payload.p1_bits, + pucch_pdu->prb_size, + true, + rm_info.E_uci_CSI1, + mod_order, + &b_csi1[0]); + + // Process CSI Part 2 if any + if (pusch_pdu->pusch_uci.csi_payload.p2_bits > 0) + nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part2_payload, + pusch_pdu->pusch_uci.csi_payload.p2_bits, + pucch_pdu->prb_size, + true, + rm_info.E_uci_CSI2, + mod_order, + &b_csi2[0]); + } + + 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 +1261,19 @@ 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, + rm_info.E_uci_CSI2, temp_codeword, G_initial_total_pusch_bits, harq_process_ul_ue->f, - b); + b_ack, + b_csi1, + b_csi2); 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,9 +1306,8 @@ 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); - if (is_uci_on_pusch) { + if (uci_present) { // UCI on PUSCH is present, so available bits are the total codeword length available_bits = G_initial_total_pusch_bits; } else { @@ -1221,7 +1324,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, available_bits, pusch_pdu->data_scrambling_id, rnti, - is_uci_on_pusch, + uci_present, uci_mapping_template, scrambled_output); if (UE->phy_sim_test_buf) { diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index d7bd25555f..3e199d2156 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -257,15 +257,15 @@ static void prepare_ue_pusch_pdu_from_matlab_vector(const bool uci_on_pusch, p_vec_bits += var.A; copy_bytes_to_packed_bits(p_vec_bits, var.oack, false, pb); - pusch_config_pdu->pusch_uci.csi_part1_bit_length = var.ocsi1; - pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part1_payload; - memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part1_payload)); + pusch_config_pdu->pusch_uci.csi_payload.p1_bits = var.ocsi1; + pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_payload.part1_payload; + memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_payload.part1_payload)); p_vec_bits += var.oack; copy_bytes_to_packed_bits(p_vec_bits, var.ocsi1, false, pb); - pusch_config_pdu->pusch_uci.csi_part2_bit_length = var.ocsi2; - pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part2_payload; - memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part2_payload)); + pusch_config_pdu->pusch_uci.csi_payload.p2_bits = var.ocsi2; + pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_payload.part2_payload; + memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_payload.part2_payload)); p_vec_bits += var.ocsi1; copy_bytes_to_packed_bits(p_vec_bits, var.ocsi2, false, pb); } @@ -1349,9 +1349,7 @@ int main(int argc, char *argv[]) .beta_offset_harq_ack = 11, .harq_ack_bit_length = 3, .harq_payload = 3, - //.csi_part1_bit_length = 4, - //.csi_part1_payload = 15 - }; + .csi_payload = {.p1_bits = 4, .part1_payload = 15, .p2_bits = 4, .part2_payload = 15}}; pusch_config_pdu->pusch_uci = pusch_uci; prepare_ue_pusch_pdu_from_matlab_vector(uci_on_pusch, uci_ulsch_matlab_vec, pusch_config_pdu, cw_buf); } @@ -1603,7 +1601,6 @@ int main(int argc, char *argv[]) } } } - round++; if (uci_on_pusch && uci_ulsch_matlab_vec && (errors_scrambling[round] == 0)) { ret = 0; printf("*************\n"); @@ -1611,6 +1608,7 @@ int main(int argc, char *argv[]) printf("*************\n"); break; } + round++; } // round if (n_trials == 1 && errors_scrambling[0] > 0) { diff --git a/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m b/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m index 0b83d211d2..c2d41dcacb 100644 --- a/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m +++ b/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m @@ -1,5 +1,5 @@ % ulsim command for same pusch config -% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -o uci_on_pusch_7.bin +% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -ouci_on_pusch_oack3_ocsi14_ocsi20.bin carrier = nrCarrierConfig; carrier.NSizeGrid = 51; @@ -32,7 +32,7 @@ pusch.DMRS.SequenceHopping = 0; pusch.BetaOffsetACK = 20; pusch.BetaOffsetCSI1 = 6.25; -pusch.BetaOffsetCSI2 = 1; +pusch.BetaOffsetCSI2 = 6.25; pusch.UCIScaling = 1; A = 37896; @@ -41,17 +41,17 @@ rv = 0; modulation = pusch.Modulation; nlayers = pusch.NumLayers; % Number of layers for decoding -oack = 7; -ocsi1 = 0; -ocsi2 = 0; +oack = 3; +ocsi1 = 4; +ocsi2 = 4; cbsInfo = nrULSCHInfo(pusch, rate, A, oack, ocsi1, ocsi2); % Get ULSCH information ack = randi([0 1],oack,1); csi1 = randi([0 1],ocsi1,1); csi2 = randi([0 1],ocsi2,1); cack = nrUCIEncode(ack,cbsInfo.GACK,pusch.Modulation); -ccsi1 = []; -ccsi2 = []; +ccsi1 = nrUCIEncode(csi1,cbsInfo.GCSI1,pusch.Modulation); +ccsi2 = nrUCIEncode(csi2,cbsInfo.GCSI2,pusch.Modulation); tb_data = randi([0 1],A,1); % Transport block CRC attachment @@ -73,7 +73,8 @@ culsch = chIn; cw_scr = nrPUSCHScramble(cw,pusch.NID,pusch.RNTI); % Write to bin file -fid = fopen('uci_on_pusch_7.bin', 'wb'); +file_name = sprintf('uci_on_pusch_oack%d_ocsi1%d_ocsi2%d.bin', oack, ocsi1, ocsi2); +fid = fopen(file_name, 'wb'); to_write = [A,oack,ocsi1,ocsi2,length(cw),length(cw_scr)]; fwrite(fid, to_write, 'uint32'); % Write the data to the binary file fwrite(fid, tb_data, "uint8"); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index f111f571ba..11dac69484 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -3399,11 +3399,11 @@ uint16_t get_ssb_start_symbol(const long band, NR_SubcarrierSpacing_t scs, int i } } - -void csi_period_offset(NR_CSI_ReportConfig_t *csirep, - struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset, - int *period, int *offset) { - +void csi_period_offset(const NR_CSI_ReportConfig_t *csirep, + const struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset, + int *period, + int *offset) +{ if(periodicityAndOffset != NULL) { NR_CSI_ResourcePeriodicityAndOffset_PR p_and_o = periodicityAndOffset->present; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 12b444539f..74baa8462f 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -285,9 +285,10 @@ unsigned int get_N_RA_RB(const unsigned int delta_f_RA_PRACH, const unsigned int void find_period_offset_SR(const NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset); -void csi_period_offset(NR_CSI_ReportConfig_t *csirep, - struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset, - int *period, int *offset); +void csi_period_offset(const NR_CSI_ReportConfig_t *csirep, + const struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset, + int *period, + int *offset); bool set_dl_ptrs_values(NR_PTRS_DownlinkConfig_t *ptrs_config, uint16_t rbSize, uint8_t mcsIndex, uint8_t mcsTable, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 65bf66505b..21b0889654 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -310,10 +310,8 @@ typedef struct { NR_PUCCH_Resource_t *pucch_resource; uint32_t ack_payload; uint8_t sr_payload; - uint64_t csi_part1_payload; - uint64_t csi_part2_payload; + nfapi_nr_ue_csi_payload_t csi_payload; int n_sr; - int n_csi; int n_harq; int n_CCE; int N_CCE; @@ -490,13 +488,6 @@ typedef struct { A_SEQUENCE_OF(NR_SearchSpace_t) list_SS; } NR_BWP_PDCCH_t; -typedef struct csi_payload { - uint64_t part1_payload; - uint64_t part2_payload; - int p1_bits; - int p2_bits; -} csi_payload_t; - typedef enum { WIDEBAND_ON_PUCCH, SUBBAND_ON_PUCCH, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 69ba897a21..72d935313c 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -124,7 +124,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info); void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info); -csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *K2); +nfapi_nr_ue_csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *K2); nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci); @@ -137,12 +137,17 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, frame_t frame, int slot); -int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch); +int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, + frame_t frame, + int slot, + nfapi_nr_ue_csi_payload_t *csi_payload, + NR_PUCCH_Resource_t **csi_pucch, + bool csi_on_pusch); -csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, +nfapi_nr_ue_csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, int csi_report_id, CSI_mapping_t mapping_type, - NR_CSI_MeasConfig_t *csi_MeasConfig); + const NR_CSI_MeasConfig_t *csi_MeasConfig); /* \brief Get payload (MAC PDU) from UE PHY @param dl_info pointer to dl indication @@ -330,7 +335,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, NR_tda_info_t *tda_info, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci, - csi_payload_t *csi_report, + nfapi_nr_ue_csi_payload_t *csi_report, RAR_grant_t *rar_grant, rnti_t rnti, int ss_type, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index b94a8758c8..672bc3c3a2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -632,7 +632,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac, /* CSI_REQUEST */ long csi_K2 = -1; - csi_payload_t csi_report = {0}; + nfapi_nr_ue_csi_payload_t csi_report = {0}; if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) csi_report = nr_ue_aperiodic_csi_reporting(mac, dci->csi_request, dci->time_domain_assignment.val, &csi_K2); @@ -1609,7 +1609,7 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0; pucch_pdu->prb_size = 1; // format 0 or 1 - int n_uci = pucch->n_sr + pucch->n_harq + pucch->n_csi; + int n_uci = pucch->n_sr + pucch->n_harq + pucch->csi_payload.p1_bits; if (n_uci > (sizeof(uint64_t) * 8)) { LOG_E(NR_MAC, "PUCCH number of UCI bits exceeds payload size\n"); return -1; @@ -1651,14 +1651,15 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->dmrs_scrambling_id = id0 != NULL ? *id0 : mac->physCellId; pucch_pdu->prb_size = compute_pucch_prb_size(2, pucchres->format.choice.format2->nrofPRBs, - pucch->n_csi, + pucch->csi_payload.p1_bits, pucch->n_harq, pucch->n_sr, pucch_Config->format2->choice.setup->maxCodeRate, 2, pucchres->format.choice.format2->nrofSymbols, 8); - pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; + pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr)) + | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; break; case NR_PUCCH_Resource__format_PR_format3 : pucch_pdu->format_type = 3; @@ -1686,14 +1687,15 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, } pucch_pdu->prb_size = compute_pucch_prb_size(3, pucchres->format.choice.format3->nrofPRBs, - pucch->n_csi, + pucch->csi_payload.p1_bits, pucch->n_harq, pucch->n_sr, pucch_Config->format3->choice.setup->maxCodeRate, 2 - pucch_pdu->pi_2bpsk, pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols, 12); - pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; + pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr)) + | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; break; case NR_PUCCH_Resource__format_PR_format4 : pucch_pdu->format_type = 4; @@ -1711,7 +1713,8 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0; pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0; } - pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; + pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr)) + | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload; break; default : LOG_E(NR_MAC, "Undefined PUCCH format \n"); @@ -2152,8 +2155,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C case NR_PUCCH_Resource__format_PR_format2: case NR_PUCCH_Resource__format_PR_format4: case NR_PUCCH_Resource__format_PR_format3: - if (res[i + 1].n_csi > 0) { - AssertFatal(res[i].n_csi == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); + if (res[i + 1].csi_payload.p1_bits > 0) { + AssertFatal(res[i].csi_payload.p1_bits == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); AssertFatal(res[i].n_harq > 0 && res[i + 1].n_harq == 0, "There is CSI in next F2 or above resource, since there is no CSI in current one, we expect HARQ in " "there and not in next\n"); @@ -2166,8 +2169,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C res[i].n_sr = res[i + 1].n_sr; res[i].sr_payload = res[i + 1].sr_payload; } - res[i].n_csi = res[i + 1].n_csi; - res[i].csi_part1_payload = res[i + 1].csi_part1_payload; + res[i].csi_payload.p1_bits = res[i + 1].csi_payload.p1_bits; + res[i].csi_payload.part1_payload = res[i + 1].csi_payload.part1_payload; res[i + 1] = res[i]; res[i] = empty; } else { @@ -2188,8 +2191,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C res[i] = empty; } } - } else if (res[i].n_csi > 0) { - AssertFatal(res[i + 1].n_csi == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); + } else if (res[i].csi_payload.p1_bits > 0) { + AssertFatal(res[i + 1].csi_payload.p1_bits == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); AssertFatal(res[i + 1].n_harq > 0 && res[i].n_harq == 0, "There is CSI in next F2 or above resource, since there is no CSI in current one, we expect HARQ in " "there and not in next\n"); @@ -2202,8 +2205,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C res[i + 1].n_sr = res[i].n_sr; res[i + 1].sr_payload = res[i].sr_payload; } - res[i + 1].n_csi = res[i].n_csi; - res[i + 1].csi_part1_payload = res[i].csi_part1_payload; + res[i + 1].csi_payload.p1_bits = res[i].csi_payload.p1_bits; + res[i + 1].csi_payload.part1_payload = res[i].csi_payload.part1_payload; res[i] = empty; } else { if (res[i + 1].n_sr > 0) { @@ -2597,68 +2600,72 @@ int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep) return 2 * Ncells * Ms * y + Ncells * Ms * k + Ms * c + s; } -int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch) +int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, + frame_t frame, + int slot, + nfapi_nr_ue_csi_payload_t *csi_payload, + NR_PUCCH_Resource_t **csi_pucch, + bool csi_on_pusch) { NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; + + if (!mac->sc_info.csi_MeasConfig || !pucch_Config) + return 0; + int num_csi = 0; + NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; - if (mac->sc_info.csi_MeasConfig) { - NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; + int csi_priority = INT_MAX; + for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) { + NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; - int csi_priority = INT_MAX; - for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) { - NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + AssertFatal(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_aperiodic + || csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_periodic, + "Not supported CSI report type\n"); - if(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_periodic) { - int period, offset; - csi_period_offset(csirep, NULL, &period, &offset); - const int n_slots_frame = mac->frame_structure.numb_slots_frame; - if (((n_slots_frame*frame + slot - offset)%period) == 0 && pucch_Config) { - int csi_res_id = -1; - for (int i = 0; i < csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.count; i++) { - const NR_PUCCH_CSI_Resource_t *pucchcsires = - csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[i]; - if (pucchcsires->uplinkBandwidthPartId == current_UL_BWP->bwp_id) { - csi_res_id = pucchcsires->pucch_Resource; - break; - } - } - if (csi_res_id < 0) { - // This CSI Report ID is not associated with current active BWP - continue; - } - NR_PUCCH_Resource_t *csi_pucch = find_pucch_resource_from_list(pucch_Config->resourceToAddModList, csi_res_id); - AssertFatal(csi_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n"); - LOG_D(NR_MAC, "Preparing CSI report in frame %d slot %d CSI report ID %d\n", frame, slot, csi_report_id); - int temp_priority = compute_csi_priority(mac, csirep); - if (num_csi > 0) { - // need to verify if we can multiplex multiple CSI report - if (pucch_Config->multi_CSI_PUCCH_ResourceList) { - AssertFatal(false, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); - } else if (temp_priority < csi_priority) { - // we discard previous report - csi_priority = temp_priority; - num_csi = 1; - csi_payload_t csi = nr_get_csi_payload(mac, csi_report_id, WIDEBAND_ON_PUCCH, csi_measconfig); - pucch->n_csi = csi.p1_bits; - pucch->csi_part1_payload = csi.part1_payload; - pucch->pucch_resource = csi_pucch; - } else - continue; - } else { - num_csi = 1; - csi_priority = temp_priority; - csi_payload_t csi = nr_get_csi_payload(mac, csi_report_id, WIDEBAND_ON_PUCCH, csi_measconfig); - pucch->n_csi = csi.p1_bits; - pucch->csi_part1_payload = csi.part1_payload; - pucch->pucch_resource = csi_pucch; - } - } + // Aperiodic CSI measurements handled in nr_ue_aperiodic_csi_reporting function + if (csirep->reportConfigType.present != NR_CSI_ReportConfig__reportConfigType_PR_periodic) + continue; + + int period, offset; + csi_period_offset(csirep, NULL, &period, &offset); + const int n_slots_frame = mac->frame_structure.numb_slots_frame; + // Check if current slot falls in the report period + if (((n_slots_frame * frame + slot - offset) % period) != 0) + continue; + + int csi_res_id = -1; + for (int i = 0; i < csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.count; i++) { + const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[i]; + if (pucchcsires->uplinkBandwidthPartId == current_UL_BWP->bwp_id) { + csi_res_id = pucchcsires->pucch_Resource; + break; } - else - AssertFatal(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_aperiodic, - "Not supported CSI report type\n"); + } + if (csi_res_id < 0) { + // This CSI Report ID is not associated with current active BWP + continue; + } + *csi_pucch = find_pucch_resource_from_list(pucch_Config->resourceToAddModList, csi_res_id); + AssertFatal(*csi_pucch != NULL, "Couldn't find PUCCH Resource ID for CSI in PUCCH resource list\n"); + LOG_D(NR_MAC, "Preparing CSI report in frame %d slot %d CSI report ID %d\n", frame, slot, csi_report_id); + int temp_priority = compute_csi_priority(mac, csirep); + if (num_csi > 0) { + // need to verify if we can multiplex multiple CSI report + if (pucch_Config->multi_CSI_PUCCH_ResourceList) { + AssertFatal(false, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n"); + } else if (temp_priority < csi_priority) { + // we discard previous report + csi_priority = temp_priority; + num_csi = 1; + *csi_payload = nr_get_csi_payload(mac, csi_report_id, csi_on_pusch ? ON_PUSCH : WIDEBAND_ON_PUCCH, csi_measconfig); + } else + continue; + } else { + num_csi = 1; + csi_priority = temp_priority; + *csi_payload = nr_get_csi_payload(mac, csi_report_id, csi_on_pusch ? ON_PUSCH : WIDEBAND_ON_PUCCH, csi_measconfig); } } return num_csi; @@ -2696,10 +2703,10 @@ static int compare_ssb_sinr(const void *a, const void *b) return mb->ssb_sinr_dB - ma->ssb_sinr_dB; } -static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig) +static nfapi_nr_ue_csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, + const struct NR_CSI_ReportConfig *csi_reportconfig, + const NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + const NR_CSI_MeasConfig_t *csi_MeasConfig) { int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on @@ -2717,7 +2724,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, } else nb_meas = 2; - struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; + const struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { @@ -2770,9 +2777,9 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, break; // resource found } } - int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8; + int max_bits = sizeof(((nfapi_nr_ue_csi_payload_t *)0)->part1_payload) * 8; AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); - csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0}; + nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0}; return csi; } @@ -2795,10 +2802,10 @@ static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp) return (diff>>1); } -static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig) +static nfapi_nr_ue_csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, + const struct NR_CSI_ReportConfig *csi_reportconfig, + const NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + const NR_CSI_MeasConfig_t *csi_MeasConfig) { int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on @@ -2817,7 +2824,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, } else nb_meas = 2; - struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; + const struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ @@ -2870,18 +2877,18 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, break; // resource found } } - int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8; + int max_bits = sizeof(((nfapi_nr_ue_csi_payload_t *)0)->part1_payload) * 8; AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); - csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0}; + nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0}; return csi; } -static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig, - CSI_mapping_t mapping_type) +static nfapi_nr_ue_csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, + const struct NR_CSI_ReportConfig *csi_reportconfig, + const NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + const NR_CSI_MeasConfig_t *csi_MeasConfig, + const CSI_mapping_t mapping_type) { int p1_bits = 0; int p2_bits = 0; @@ -2949,13 +2956,13 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, } } AssertFatal(p1_bits <= 32 && p2_bits <= 32, "Not supporting CSI report with more than 32 bits\n"); - csi_payload_t csi = {.part1_payload = temp_payload_1, .part2_payload = temp_payload_2, .p1_bits = p1_bits, csi.p2_bits = p2_bits}; + nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload_1, .part2_payload = temp_payload_2, .p1_bits = p1_bits, csi.p2_bits = p2_bits}; return csi; } -static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, +static nfapi_nr_ue_csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, + const struct NR_CSI_ReportConfig *csi_reportconfig, + const NR_CSI_ResourceConfigId_t csi_ResourceConfigId, const NR_CSI_MeasConfig_t *csi_MeasConfig) { int n_bits = 0; @@ -3002,17 +3009,17 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, } } AssertFatal(n_bits <= 32, "Not supporting CSI report with more than 32 bits\n"); - csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = n_bits, csi.p2_bits = 0}; + nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = n_bits, csi.p2_bits = 0}; return csi; } -csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, - int csi_report_id, - CSI_mapping_t mapping_type, - NR_CSI_MeasConfig_t *csi_MeasConfig) +nfapi_nr_ue_csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, + int csi_report_id, + CSI_mapping_t mapping_type, + const NR_CSI_MeasConfig_t *csi_MeasConfig) { AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n"); - csi_payload_t csi = {0}; + nfapi_nr_ue_csi_payload_t csi = {0}; struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 2818c20c37..fcc977d9e5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -341,6 +341,26 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf } } +static void fill_pusch_uci_struct(const NR_PUSCH_Config_t *pusch_Config, + const nfapi_nr_ue_csi_payload_t *csi_payload, + nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu) +{ + pusch_config_pdu->pusch_uci.csi_payload = *csi_payload; + AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n"); + NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup; + AssertFatal(onPusch && onPusch->betaOffsets && onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic, + "Only semistatic beta offset is supported\n"); + NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic; + + pusch_config_pdu->pusch_uci.beta_offset_csi1 = pusch_config_pdu->pusch_uci.csi_payload.p1_bits < 12 + ? *beta_offsets->betaOffsetCSI_Part1_Index1 + : *beta_offsets->betaOffsetCSI_Part1_Index2; + pusch_config_pdu->pusch_uci.beta_offset_csi2 = pusch_config_pdu->pusch_uci.csi_payload.p2_bits < 12 + ? *beta_offsets->betaOffsetCSI_Part2_Index1 + : *beta_offsets->betaOffsetCSI_Part2_Index2; + pusch_config_pdu->pusch_uci.alpha_scaling = onPusch->scaling; +} + // Configuration of Msg3 PDU according to clauses: // - 8.3 of 3GPP TS 38.213 version 16.3.0 Release 16 // - 6.1.2.2 of TS 38.214 @@ -353,7 +373,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, NR_tda_info_t *tda_info, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci, - csi_payload_t *csi_report, + nfapi_nr_ue_csi_payload_t *csi_report, RAR_grant_t *rar_grant, rnti_t rnti, int ss_type, @@ -534,29 +554,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->ulsch_indicator = dci->ulsch_indicator; if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) { AssertFatal(csi_report, "CSI report needs to be present in case of CSI request\n"); - pusch_config_pdu->pusch_uci.csi_part1_bit_length = csi_report->p1_bits; - pusch_config_pdu->pusch_uci.csi_part1_payload = csi_report->part1_payload; - pusch_config_pdu->pusch_uci.csi_part2_bit_length = csi_report->p2_bits; - pusch_config_pdu->pusch_uci.csi_part2_payload = csi_report->part2_payload; - AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n"); - NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup; - AssertFatal(onPusch && - onPusch->betaOffsets && - onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic, - "Only semistatic beta offset is supported\n"); - NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic; - - pusch_config_pdu->pusch_uci.beta_offset_csi1 = pusch_config_pdu->pusch_uci.csi_part1_bit_length < 12 ? - *beta_offsets->betaOffsetCSI_Part1_Index1 : - *beta_offsets->betaOffsetCSI_Part1_Index2; - pusch_config_pdu->pusch_uci.beta_offset_csi2 = pusch_config_pdu->pusch_uci.csi_part2_bit_length < 12 ? - *beta_offsets->betaOffsetCSI_Part2_Index1 : - *beta_offsets->betaOffsetCSI_Part2_Index2; - pusch_config_pdu->pusch_uci.alpha_scaling = onPusch->scaling; - } - else { - pusch_config_pdu->pusch_uci.csi_part1_bit_length = 0; - pusch_config_pdu->pusch_uci.csi_part2_bit_length = 0; + fill_pusch_uci_struct(pusch_Config, csi_report, pusch_config_pdu); + } else { + pusch_config_pdu->pusch_uci.csi_payload.p1_bits = 0; + pusch_config_pdu->pusch_uci.csi_payload.p2_bits = 0; } pusch_config_pdu->pusch_uci.harq_ack_bit_length = 0; @@ -864,13 +865,13 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, return 0; } -csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *k2) +nfapi_nr_ue_csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *k2) { NR_CSI_AperiodicTriggerStateList_t *aperiodicTriggerStateList = mac->sc_info.aperiodicTriggerStateList; AssertFatal(aperiodicTriggerStateList, "Received CSI request via DCI but aperiodicTriggerStateList is not present\n"); int n_states = aperiodicTriggerStateList->list.count; int n_ts = csi_request.nbits; - csi_payload_t csi = {0}; + nfapi_nr_ue_csi_payload_t csi = {0}; AssertFatal(n_states <= ((1 << n_ts) - 1), "Case of subselection indication of trigger states not supported yet\n"); int num_trig = 0; for (int i = 0; i < n_ts; i++) { @@ -891,8 +892,8 @@ csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t c if (report_config->reportConfigId == id) { struct NR_CSI_ReportConfig__reportConfigType__aperiodic__reportSlotOffsetList *offset_list = &report_config->reportConfigType.choice.aperiodic->reportSlotOffsetList; AssertFatal(tda < offset_list->list.count, "TDA index from DCI %d exceeds slot offset list %d\n", tda, offset_list->list.count); - if (k2 == NULL || *k2 < *offset_list->list.array[tda]) - k2 = offset_list->list.array[tda]; + if (*k2 < *offset_list->list.array[tda]) + *k2 = *offset_list->list.array[tda]; found = c; break; } @@ -1791,9 +1792,17 @@ static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule UCI on PUSCH\n"); } } - if (pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0) { - // To support this we would need to shift some bits into CSI part2 -> need to change the logic - AssertFatal(pucch->n_csi == 0, "Multiplexing periodic CSI on PUSCH not supported\n"); + + AssertFatal(pusch_pdu->pusch_uci.csi_payload.p1_bits == 0, "PUSCH already has CSI report\n"); + + // Check if this PUCCH has CSI report to send. If so, multiplex it on PUSCH + if (pucch->csi_payload.p1_bits > 0) { + nfapi_nr_ue_csi_payload_t csi_payload = {0}; + NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config; + NR_PUCCH_Resource_t *csi_pucch = NULL; + nr_get_csi_measurements(mac, frame_tx, slot_tx, &csi_payload, &csi_pucch, true); + fill_pusch_uci_struct(pusch_Config, &csi_payload, pusch_pdu); + mux_done = true; } release_ul_config(ulcfg_pdu, false); @@ -1824,7 +1833,7 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot // CSI int csi_res = 0; if (mac->state == UE_CONNECTED) - csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res]); + csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res].csi_payload, &pucch[num_res].pucch_resource, false); if (csi_res > 0) { num_res += csi_res; } @@ -1845,14 +1854,14 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot } for (int j = 0; j < num_res; j++) { - if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) { + if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].csi_payload.p1_bits != 0) { LOG_D(NR_MAC, "%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n", frame, slot, pucch[j].n_harq, pucch[j].n_sr, - pucch[j].n_csi); + pucch[j].csi_payload.p1_bits); // checking if we need to schedule pucch[j] on PUSCH if (schedule_uci_on_pusch(mac, frame, slot, &pucch[j], mac->current_UL_BWP)) @@ -2696,6 +2705,18 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) } } +static void get_pusch_frame_slot(const int current_frame, + const int current_slot, + const int k2, + const int delta, + const int slots_per_frame, + frame_t *frame_tx, + int *slot_tx) +{ + *slot_tx = (current_slot + k2 + delta) % slots_per_frame; + *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; +} + // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, // - where K2 is the offset between the slot in which UL DCI is received and the slot @@ -2734,8 +2755,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu)); - *slot_tx = (current_slot + k2 + delta) % slots_per_frame; - *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; + get_pusch_frame_slot(current_frame, current_slot, k2, delta, slots_per_frame, frame_tx, slot_tx); } else { AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " @@ -2752,8 +2772,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, } // Calculate TX slot and frame - *slot_tx = (current_slot + k2) % slots_per_frame; - *frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER; + get_pusch_frame_slot(current_frame, current_slot, k2, 0, slots_per_frame, frame_tx, slot_tx); } LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta);