diff --git a/lib/include/srsran/phy/phch/phch_cfg_nr.h b/lib/include/srsran/phy/phch/phch_cfg_nr.h index 3171835dc..99d028bfe 100644 --- a/lib/include/srsran/phy/phch/phch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/phch_cfg_nr.h @@ -164,6 +164,11 @@ typedef struct { uint32_t csi1_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. uint32_t csi2_index1; ///< Use for up to 11 CSI bits. Set to 13 if absent. uint32_t csi2_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. + + /// Fix values for testing purposes + float fix_ack; ///< Set to a non-zero value for fixing a beta offset value + float fix_csi1; + float fix_csi2; } srsran_beta_offsets_t; /** @@ -238,13 +243,11 @@ typedef struct SRSRAN_API { /// PUSCH only parameters srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration bool enable_transform_precoder; - float beta_harq_ack_offset; - float beta_csi_part1_offset; - float beta_csi_part2_offset; - float scaling; bool freq_hopping_enabled; } srsran_sch_cfg_nr_t; -SRSRAN_API uint32_t srsran_phch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len); +SRSRAN_API uint32_t srsran_sch_cfg_nr_nof_re(const srsran_sch_cfg_nr_t* sch_cfg); + +SRSRAN_API uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len); #endif // SRSRAN_PHCH_CFG_NR_H diff --git a/lib/include/srsran/phy/phch/pusch_nr.h b/lib/include/srsran/phy/phch/pusch_nr.h index 265cd466a..f61755caa 100644 --- a/lib/include/srsran/phy/phch/pusch_nr.h +++ b/lib/include/srsran/phy/phch/pusch_nr.h @@ -51,7 +51,6 @@ typedef struct SRSRAN_API { bool meas_time_en; uint32_t meas_time_us; srsran_re_pattern_t dmrs_re_pattern; - srsran_uci_cfg_nr_t uci_cfg; ///< Internal UCI bits configuration uint8_t* g_ulsch; ///< Temporal Encoded UL-SCH data uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits diff --git a/lib/include/srsran/phy/phch/ra_nr.h b/lib/include/srsran/phy/phch/ra_nr.h index 344ef060d..a2ddd5042 100644 --- a/lib/include/srsran/phy/phch/ra_nr.h +++ b/lib/include/srsran/phy/phch/ra_nr.h @@ -128,12 +128,14 @@ SRSRAN_API int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrie * * @remark Implement procedure described in TS 38.213 9.3 UCI reporting in physical uplink shared channel * + * @param carrier Carrier information struct * @param pusch_hl_cfg PUSCH configuration provided by higher layers * @param uci_cfg Uplink Control Information configuration for this PUSCH transmission * @param pusch_cfg PUSCH configuration after applying the procedure * @return SRSRAN_SUCCESS if the procedure is successful, SRSRAN_ERROR code otherwise */ -SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, +SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier, + const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_uci_cfg_nr_t* uci_cfg, srsran_sch_cfg_nr_t* pusch_cfg); diff --git a/lib/include/srsran/phy/phch/sch_cfg_nr.h b/lib/include/srsran/phy/phch/sch_cfg_nr.h index 178cd57f2..9a3c580f8 100644 --- a/lib/include/srsran/phy/phch/sch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/sch_cfg_nr.h @@ -32,8 +32,8 @@ typedef struct SRSRAN_API { int rv; ///< Redundancy version int ndi; ///< New Data Indicator int pid; ///< HARQ Process ID - uint32_t nof_re; ///< Number of available resource elements to send, known as N_RE - uint32_t nof_bits; ///< Number of available bits to send, known as G + uint32_t nof_re; ///< Number of available resource elements to transmit ULSCH (data) and UCI (control) + uint32_t nof_bits; ///< Number of available bits to send ULSCH uint32_t cw_idx; bool enabled; diff --git a/lib/include/srsran/phy/phch/uci_cfg_nr.h b/lib/include/srsran/phy/phch/uci_cfg_nr.h index b47e65507..7330333d5 100644 --- a/lib/include/srsran/phy/phch/uci_cfg_nr.h +++ b/lib/include/srsran/phy/phch/uci_cfg_nr.h @@ -62,6 +62,7 @@ typedef struct { float alpha; ///< Higher layer parameter scaling float beta_harq_ack_offset; float beta_csi1_offset; + float beta_csi2_offset; uint32_t nof_re; bool csi_part2_present; } srsran_uci_nr_pusch_cfg_t; diff --git a/lib/src/phy/phch/phch_cfg_nr.c b/lib/src/phy/phch/phch_cfg_nr.c index 4cf2d0f19..c4b427b3a 100644 --- a/lib/src/phy/phch/phch_cfg_nr.c +++ b/lib/src/phy/phch/phch_cfg_nr.c @@ -216,28 +216,26 @@ static uint32_t phch_cfg_rvd_to_str(const srsran_re_pattern_list_t* pattern_list return len; } -static uint32_t phch_cfg_uci_to_str(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len) +static uint32_t phch_cfg_uci_to_str(const srsran_uci_cfg_nr_t* uci, char* str, uint32_t str_len) { uint32_t len = 0; - if (srsran_uci_nr_total_bits(&sch_cfg->uci) == 0) { + if (srsran_uci_nr_total_bits(uci) == 0) { return len; } - len = srsran_print_check(str, str_len, len, " UCI:\n", sch_cfg->scaling); - len = srsran_print_check(str, str_len, len, " scaling=%.2f\n", sch_cfg->scaling); - len = srsran_print_check(str, str_len, len, " beta_csi_part1_offset=%.2f\n", sch_cfg->beta_csi_part1_offset); - len = srsran_print_check(str, str_len, len, " beta_csi_part2_offset=%.2f\n", sch_cfg->beta_csi_part2_offset); - len = srsran_print_check(str, str_len, len, " beta_harq_ack_offset=%.2f\n", sch_cfg->beta_harq_ack_offset); - - len = srsran_print_check( - str, str_len, len, " o_csi1=%d\n", srsran_csi_part1_nof_bits(sch_cfg->uci.csi, sch_cfg->uci.nof_csi)); - len = srsran_print_check(str, str_len, len, " o_ack=%d\n", sch_cfg->uci.o_ack); + len = srsran_print_check(str, str_len, len, " UCI:\n"); + len = srsran_print_check(str, str_len, len, " alpha=%.2f\n", uci->pusch.alpha); + len = srsran_print_check(str, str_len, len, " beta_harq_ack_offset=%.2f\n", uci->pusch.beta_harq_ack_offset); + len = srsran_print_check(str, str_len, len, " beta_csi_part1_offset=%.2f\n", uci->pusch.beta_csi1_offset); + len = srsran_print_check(str, str_len, len, " beta_csi_part2_offset=%.2f\n", uci->pusch.beta_csi1_offset); + len = srsran_print_check(str, str_len, len, " o_csi1=%d\n", srsran_csi_part1_nof_bits(uci->csi, uci->nof_csi)); + len = srsran_print_check(str, str_len, len, " o_ack=%d\n", uci->o_ack); return len; } -uint32_t srsran_phch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len) +uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len) { uint32_t len = 0; @@ -258,7 +256,7 @@ uint32_t srsran_phch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, len += phch_cfg_rvd_to_str(&sch_cfg->rvd_re, &str[len], str_len - len); // UCI configuration - len += phch_cfg_uci_to_str(sch_cfg, &str[len], str_len - len); + len += phch_cfg_uci_to_str(&sch_cfg->uci, &str[len], str_len - len); return len; } diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index 2b086d76d..908e38273 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -328,121 +328,6 @@ pusch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cf return cinit; } -static inline int pusch_nr_fill_uci_cfg(srsran_pusch_nr_t* q, const srsran_sch_cfg_nr_t* cfg) -{ - if (cfg->grant.nof_prb == 0) { - ERROR("Invalid number of PRB (%d)", cfg->grant.nof_prb); - return SRSRAN_ERROR; - } - - // Initially, copy all fields - q->uci_cfg = cfg->uci; - - // Reset UCI PUSCH configuration - SRSRAN_MEM_ZERO(&q->uci_cfg.pusch, srsran_uci_nr_pusch_cfg_t, 1); - - // Get DMRS symbol indexes - uint32_t nof_dmrs_l = 0; - uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {}; - int n = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, &cfg->grant, dmrs_l); - if (n < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } - nof_dmrs_l = (uint32_t)n; - - // Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS - // Starts at first OFDM symbol carrying DMRS - for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) { - // Check if it is not carrying DMRS... - if (l != dmrs_l[dmrs_l_idx]) { - // Set value and stop iterating - q->uci_cfg.pusch.l0 = l; - break; - } - - // Move to the next DMRS OFDM symbol index - if (dmrs_l_idx < nof_dmrs_l) { - dmrs_l_idx++; - } - } - - // Find OFDM symbol index of the first OFDM symbol that does not carry DMRS - // Starts at first OFDM symbol of the PUSCH transmission - for (uint32_t l = cfg->grant.S, dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) { - // Check if it is not carrying DMRS... - if (l != dmrs_l[dmrs_l_idx]) { - q->uci_cfg.pusch.l1 = l; - break; - } - - // Move to the next DMRS OFDM symbol index - if (dmrs_l_idx < nof_dmrs_l) { - dmrs_l_idx++; - } - } - - // Number of DMRS per PRB - uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(cfg->grant.nof_dmrs_cdm_groups_without_data, cfg->dmrs.type); - - // Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1 - for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { - // Skip if OFDM symbol is outside of the PUSCH transmission - if (l < cfg->grant.S || l >= (cfg->grant.S + cfg->grant.L)) { - q->uci_cfg.pusch.M_pusch_sc[l] = 0; - q->uci_cfg.pusch.M_uci_sc[l] = 0; - continue; - } - - // OFDM symbol carries DMRS - if (l == dmrs_l[dmrs_l_idx]) { - // Calculate PUSCH RE candidates - q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs); - - // The Number of RE candidates for UCI are 0 - q->uci_cfg.pusch.M_uci_sc[l] = 0; - - // Advance DMRS symbol index - dmrs_l_idx++; - - // Skip to next symbol - continue; - } - - // Number of RE for Phase Tracking Reference Signals (PT-RS) - uint32_t M_ptrs_sc = 0; // Not implemented yet - - // Number of RE given by the grant - q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * SRSRAN_NRE; - - // Calculate the number of UCI candidates - q->uci_cfg.pusch.M_uci_sc[l] = q->uci_cfg.pusch.M_pusch_sc[l] - M_ptrs_sc; - } - - // Generate SCH Transport block information - srsran_sch_nr_tb_info_t sch_tb_info = {}; - if (srsran_sch_nr_fill_tb_info(&q->carrier, &cfg->sch_cfg, &cfg->grant.tb[0], &sch_tb_info) < SRSRAN_SUCCESS) { - ERROR("Generating TB info"); - return SRSRAN_ERROR; - } - - // Calculate the sum of codeblock sizes - for (uint32_t i = 0; i < sch_tb_info.C; i++) { - // Accumulate codeblock size if mask is enabled - q->uci_cfg.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0; - } - - // Set other PUSCH parameters - q->uci_cfg.pusch.modulation = cfg->grant.tb[0].mod; - q->uci_cfg.pusch.nof_layers = cfg->grant.nof_layers; - q->uci_cfg.pusch.R = (float)cfg->grant.tb[0].R; - q->uci_cfg.pusch.alpha = cfg->scaling; - q->uci_cfg.pusch.beta_harq_ack_offset = cfg->beta_harq_ack_offset; - q->uci_cfg.pusch.beta_csi1_offset = cfg->beta_csi_part1_offset; - q->uci_cfg.pusch.nof_re = cfg->grant.tb[0].nof_re; - - return SRSRAN_SUCCESS; -} - // Implements TS 38.212 6.2.7 Data and control multiplexing (for NR-PUSCH) static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t* cfg) { @@ -479,7 +364,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t* if (cfg->o_ack <= 2) { // the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause // 6.3.2.4.2.1, by setting O_ACK = 2 ; - G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, 2); + G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&cfg->pusch, 2); // Disable non reserved HARQ-ACK bits G_ack = 0; @@ -695,7 +580,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // Encode HARQ-ACK bits - int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &q->uci_cfg, uci, q->g_ack); + int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &cfg->uci, uci, q->g_ack); if (E_uci_ack < SRSRAN_SUCCESS) { ERROR("Error encoding HARQ-ACK bits"); return SRSRAN_ERROR; @@ -703,7 +588,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, q->G_ack = (uint32_t)E_uci_ack; // Encode CSI part 1 - int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &q->uci_cfg, uci, q->g_csi1); + int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &cfg->uci, uci, q->g_csi1); if (E_uci_csi1 < SRSRAN_SUCCESS) { ERROR("Error encoding HARQ-ACK bits"); return SRSRAN_ERROR; @@ -715,7 +600,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, q->G_csi2 = 0; // Generate PUSCH UCI/UL-SCH multiplexing - if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) { + if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) { ERROR("Error generating PUSCH mux tables"); return SRSRAN_ERROR; } @@ -727,7 +612,8 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // Multiplex UL-SCH with UCI only if it is necessary - uint8_t* b = q->g_ulsch; + uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod); + uint8_t* b = q->g_ulsch; if (q->uci_mux) { // Change b location b = q->b[tb->cw_idx]; @@ -755,15 +641,15 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("b="); - srsran_vec_fprint_b(stdout, b, tb->nof_bits); + srsran_vec_fprint_b(stdout, b, nof_bits); } // 7.3.1.1 Scrambling uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx); - srsran_sequence_apply_bit(b, q->b[tb->cw_idx], tb->nof_bits, cinit); + srsran_sequence_apply_bit(b, q->b[tb->cw_idx], nof_bits, cinit); // Special Scrambling condition - if (q->uci_cfg.o_ack <= 2) { + if (cfg->uci.o_ack <= 2) { for (uint32_t i = 0; i < q->G_ack; i++) { uint32_t idx = q->pos_ack[i]; if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) { @@ -777,7 +663,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // 7.3.1.2 Modulation - srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits); + srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], nof_bits); if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("d="); @@ -795,6 +681,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, { // Check input pointers if (!q || !cfg || !grant || !data || !sf_symbols) { + ERROR("Invalid inputs"); return SRSRAN_ERROR_INVALID_INPUTS; } @@ -815,12 +702,6 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, return SRSRAN_ERROR; } - // Fill UCI configuration for PUSCH configuration - if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { - ERROR("Error filling UCI configuration for PUSCH"); - return SRSRAN_ERROR; - } - // 7.3.1.1 and 7.3.1.2 uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { @@ -895,8 +776,11 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, srsran_vec_fprint_c(stdout, q->d[tb->cw_idx], tb->nof_re); } + // Total number of bits + uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod); + // Calculate HARQ-ACK bits - int n = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, q->uci_cfg.o_ack); + int n = srsran_uci_nr_pusch_ack_nof_bits(&cfg->uci.pusch, cfg->uci.o_ack); if (n < SRSRAN_SUCCESS) { ERROR("Calculating G_ack"); return SRSRAN_ERROR; @@ -904,7 +788,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, q->G_ack = (uint32_t)n; // Calculate CSI part 1 bits - n = srsran_uci_nr_pusch_csi1_nof_bits(&q->uci_cfg); + n = srsran_uci_nr_pusch_csi1_nof_bits(&cfg->uci); if (n < SRSRAN_SUCCESS) { ERROR("Calculating G_csi1"); return SRSRAN_ERROR; @@ -916,7 +800,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, q->G_csi2 = 0; // Generate PUSCH UCI/UL-SCH multiplexing - if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) { + if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) { ERROR("Error generating PUSCH mux tables"); return SRSRAN_ERROR; } @@ -929,16 +813,15 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // EVM if (q->evm_buffer != NULL) { - res->evm[tb->cw_idx] = - srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits); + res->evm[tb->cw_idx] = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, nof_bits); } // Descrambling - srsran_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); + srsran_sequence_apply_c(llr, llr, nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("b="); - srsran_vec_fprint_bs(stdout, llr, tb->nof_bits); + srsran_vec_fprint_bs(stdout, llr, nof_bits); } // Demultiplex UCI only if necessary @@ -948,7 +831,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, for (uint32_t i = 0; i < q->G_ulsch; i++) { g_ulsch[i] = -llr[q->pos_ulsch[i]]; } - for (uint32_t i = q->G_ulsch; i < tb->nof_bits; i++) { + for (uint32_t i = q->G_ulsch; i < nof_bits; i++) { g_ulsch[i] = 0; } @@ -972,7 +855,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Decode HARQ-ACK if (q->G_ack) { - if (srsran_uci_nr_decode_pusch_ack(&q->uci, &q->uci_cfg, g_ack, &res->uci)) { + if (srsran_uci_nr_decode_pusch_ack(&q->uci, &cfg->uci, g_ack, &res->uci)) { ERROR("Error in UCI decoding"); return SRSRAN_ERROR; } @@ -980,7 +863,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Decode CSI part 1 if (q->G_csi1) { - if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &q->uci_cfg, g_csi1, &res->uci)) { + if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &cfg->uci, g_csi1, &res->uci)) { ERROR("Error in UCI decoding"); return SRSRAN_ERROR; } @@ -992,13 +875,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Change LLR pointer llr = g_ulsch; } else { - for (uint32_t i = 0; i < tb->nof_bits; i++) { + for (uint32_t i = 0; i < nof_bits; i++) { llr[i] *= -1; } } // Decode Ul-SCH - if (tb->nof_bits != 0) { + if (nof_bits != 0) { if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) { ERROR("Error in SCH decoding"); return SRSRAN_ERROR; @@ -1037,12 +920,6 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, return SRSRAN_ERROR; } - // Fill UCI configuration for PUSCH configuration - if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { - ERROR("Error filling UCI configuration for PUSCH"); - return SRSRAN_ERROR; - } - uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { nof_cw += grant->tb[tb].enabled ? 1 : 0; diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index fd3ce41c0..e5f2cdae0 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -16,6 +16,7 @@ #include "srsran/phy/phch/pdsch_nr.h" #include "srsran/phy/phch/ra_dl_nr.h" #include "srsran/phy/phch/ra_ul_nr.h" +#include "srsran/phy/phch/uci_nr.h" #include "srsran/phy/utils/debug.h" typedef struct { @@ -814,6 +815,10 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_offsets, const srsran_uci_cfg_nr_t* uci_cfg) { + if (isnormal(beta_offsets->fix_ack)) { + return beta_offsets->fix_ack; + } + // Select Beta Offset index from the number of HARQ-ACK bits uint32_t beta_offset_index = beta_offsets->ack_index1; if (uci_cfg->o_ack > 11) { @@ -843,6 +848,11 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_ const srsran_uci_cfg_nr_t* uci_cfg, bool part2) { + float fix_beta_offset = part2 ? beta_offsets->fix_csi2 : beta_offsets->fix_csi1; + if (isnormal(fix_beta_offset)) { + return fix_beta_offset; + } + // Calculate number of CSI bits; CSI part 2 is not supported. uint32_t O_csi = part2 ? 0 : srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); @@ -865,35 +875,162 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_ return ra_nr_beta_offset_csi_table[beta_offset_index]; } -int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, +int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier, + const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_uci_cfg_nr_t* uci_cfg, srsran_sch_cfg_nr_t* pusch_cfg) { - // Select beta offsets - pusch_cfg->beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); - if (!isnormal(pusch_cfg->beta_harq_ack_offset)) { + if (pusch_cfg->grant.nof_prb == 0) { + ERROR("Invalid number of PRB (%d)", pusch_cfg->grant.nof_prb); return SRSRAN_ERROR; } - pusch_cfg->beta_csi_part1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); - if (!isnormal(pusch_cfg->beta_csi_part1_offset)) { - return SRSRAN_ERROR; - } - - pusch_cfg->beta_csi_part2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); - if (!isnormal(pusch_cfg->beta_csi_part2_offset)) { - return SRSRAN_ERROR; - } - - // pusch_cfg->beta_csi_part2_offset = pusch_hl_cfg->beta_offset_csi2; - pusch_cfg->scaling = pusch_hl_cfg->scaling; - if (!isnormal(pusch_cfg->scaling)) { - ERROR("Invalid Scaling (%f)", pusch_cfg->scaling); - return SRSRAN_ERROR; - } - - // Copy UCI configuration + // Initially, copy all fields pusch_cfg->uci = *uci_cfg; + // Reset UCI PUSCH configuration + SRSRAN_MEM_ZERO(&pusch_cfg->uci.pusch, srsran_uci_nr_pusch_cfg_t, 1); + + // Get DMRS symbol indexes + uint32_t nof_dmrs_l = 0; + uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {}; + int n = srsran_dmrs_sch_get_symbols_idx(&pusch_cfg->dmrs, &pusch_cfg->grant, dmrs_l); + if (n < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + nof_dmrs_l = (uint32_t)n; + + // Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS + // Starts at first OFDM symbol carrying DMRS + for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) { + // Check if it is not carrying DMRS... + if (l != dmrs_l[dmrs_l_idx]) { + // Set value and stop iterating + pusch_cfg->uci.pusch.l0 = l; + break; + } + + // Move to the next DMRS OFDM symbol index + if (dmrs_l_idx < nof_dmrs_l) { + dmrs_l_idx++; + } + } + + // Find OFDM symbol index of the first OFDM symbol that does not carry DMRS + // Starts at first OFDM symbol of the PUSCH transmission + for (uint32_t l = pusch_cfg->grant.S, dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) { + // Check if it is not carrying DMRS... + if (l != dmrs_l[dmrs_l_idx]) { + pusch_cfg->uci.pusch.l1 = l; + break; + } + + // Move to the next DMRS OFDM symbol index + if (dmrs_l_idx < nof_dmrs_l) { + dmrs_l_idx++; + } + } + + // Number of DMRS per PRB + uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(pusch_cfg->grant.nof_dmrs_cdm_groups_without_data, pusch_cfg->dmrs.type); + + // Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1 + for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { + // Skip if OFDM symbol is outside of the PUSCH transmission + if (l < pusch_cfg->grant.S || l >= (pusch_cfg->grant.S + pusch_cfg->grant.L)) { + pusch_cfg->uci.pusch.M_pusch_sc[l] = 0; + pusch_cfg->uci.pusch.M_uci_sc[l] = 0; + continue; + } + + // OFDM symbol carries DMRS + if (l == dmrs_l[dmrs_l_idx]) { + // Calculate PUSCH RE candidates + pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs); + + // The Number of RE candidates for UCI are 0 + pusch_cfg->uci.pusch.M_uci_sc[l] = 0; + + // Advance DMRS symbol index + dmrs_l_idx++; + + // Skip to next symbol + continue; + } + + // Number of RE for Phase Tracking Reference Signals (PT-RS) + uint32_t M_ptrs_sc = 0; // Not implemented yet + + // Number of RE given by the grant + pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * SRSRAN_NRE; + + // Calculate the number of UCI candidates + pusch_cfg->uci.pusch.M_uci_sc[l] = pusch_cfg->uci.pusch.M_pusch_sc[l] - M_ptrs_sc; + } + + // Generate SCH Transport block information + srsran_sch_nr_tb_info_t sch_tb_info = {}; + if (srsran_sch_nr_fill_tb_info(carrier, &pusch_cfg->sch_cfg, &pusch_cfg->grant.tb[0], &sch_tb_info) < + SRSRAN_SUCCESS) { + ERROR("Generating TB info"); + return SRSRAN_ERROR; + } + + // Calculate the sum of codeblock sizes + for (uint32_t i = 0; i < sch_tb_info.C; i++) { + // Accumulate codeblock size if mask is enabled + pusch_cfg->uci.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0; + } + + // Set other PUSCH parameters + pusch_cfg->uci.pusch.modulation = pusch_cfg->grant.tb[0].mod; + pusch_cfg->uci.pusch.nof_layers = pusch_cfg->grant.nof_layers; + pusch_cfg->uci.pusch.R = (float)pusch_cfg->grant.tb[0].R; + pusch_cfg->uci.pusch.nof_re = pusch_cfg->grant.tb[0].nof_re; + + // Select beta offsets + pusch_cfg->uci.pusch.beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); + if (!isnormal(pusch_cfg->uci.pusch.beta_harq_ack_offset)) { + return SRSRAN_ERROR; + } + + pusch_cfg->uci.pusch.beta_csi1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); + if (!isnormal(pusch_cfg->uci.pusch.beta_csi1_offset)) { + return SRSRAN_ERROR; + } + + pusch_cfg->uci.pusch.beta_csi2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); + if (!isnormal(pusch_cfg->uci.pusch.beta_csi2_offset)) { + return SRSRAN_ERROR; + } + + pusch_cfg->uci.pusch.alpha = pusch_hl_cfg->scaling; + if (!isnormal(pusch_cfg->uci.pusch.alpha)) { + ERROR("Invalid Scaling (%f)", pusch_cfg->uci.pusch.alpha); + return SRSRAN_ERROR; + } + + // Calculate number of UCI encoded bits + int Gack = 0; + if (pusch_cfg->uci.o_ack > 2) { + Gack = srsran_uci_nr_pusch_ack_nof_bits(&pusch_cfg->uci.pusch, pusch_cfg->uci.o_ack); + if (Gack < SRSRAN_SUCCESS) { + ERROR("Error calculating Qdack"); + return SRSRAN_ERROR; + } + } + int Gcsi1 = srsran_uci_nr_pusch_csi1_nof_bits(&pusch_cfg->uci); + if (Gcsi1 < SRSRAN_SUCCESS) { + ERROR("Error calculating Qdack"); + return SRSRAN_ERROR; + } + int Gcsi2 = 0; // NOT supported + + // Update Number of TB encoded bits + for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { + pusch_cfg->grant.tb[i].nof_bits = + pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2; + } + return SRSRAN_SUCCESS; } diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index 1e91e9e52..0c00392e6 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -187,9 +187,11 @@ int main(int argc, char** argv) mcs_end = SRSRAN_MIN(mcs + 1, mcs_end); } - pusch_cfg.scaling = 0.5f; - pusch_cfg.beta_harq_ack_offset = 2.0f; - pusch_cfg.beta_csi_part1_offset = 2.0f; + srsran_sch_hl_cfg_nr_t sch_hl_cfg = {}; + sch_hl_cfg.scaling = 1.0f; + sch_hl_cfg.beta_offsets.fix_ack = 12.625f; + sch_hl_cfg.beta_offsets.fix_csi1 = 2.25f; + sch_hl_cfg.beta_offsets.fix_csi2 = 2.25f; if (srsran_chest_dl_res_init(&chest, carrier.nof_prb) < SRSRAN_SUCCESS) { ERROR("Initiating chest"); @@ -245,6 +247,11 @@ int main(int argc, char** argv) data_rx.uci.csi[0].none = csi_report_rx; } + if (srsran_ra_ul_set_grant_uci_nr(&carrier, &sch_hl_cfg, &pusch_cfg.uci, &pusch_cfg) < SRSRAN_SUCCESS) { + ERROR("Setting UCI"); + goto clean_exit; + } + if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols) < SRSRAN_SUCCESS) { ERROR("Error encoding"); goto clean_exit; @@ -345,7 +352,7 @@ int main(int argc, char** argv) srsran_pusch_nr_rx_info(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &data_rx, str, (uint32_t)sizeof(str)); char str_extra[2048]; - srsran_phch_cfg_nr_info(&pusch_cfg, str_extra, (uint32_t)sizeof(str_extra)); + srsran_sch_cfg_nr_info(&pusch_cfg, str_extra, (uint32_t)sizeof(str_extra)); INFO("PUSCH: %s\n%s", str, str_extra); } diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index b20b65bf1..6f862cf8f 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -383,16 +383,18 @@ static int uci_nr_decode_1_bit(srsran_uci_nr_t* q, } // Correlate LLR - float corr = 0.0f; - float pwr = 0.0f; + float corr = 0.0f; + float pwr = 0.0f; + uint32_t count = 0; for (uint32_t i = 0; i < E; i += Qm) { float t = (float)llr[i]; corr += t; pwr += t * t; + count++; } // Normalise correlation - float norm_corr = Qm * corr / (E * sqrtf(pwr)); + float norm_corr = fabsf(corr) / sqrtf(pwr * count); // Take decoded decision with threshold *decoded_ok = (norm_corr > q->one_bit_threshold); diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index 35871f720..96f377979 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -453,7 +453,7 @@ int main(int argc, char** argv) srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str, (uint32_t)sizeof(str)); char str_extra[2048]; - srsran_phch_cfg_nr_info(&pdsch_cfg, str_extra, (uint32_t)sizeof(str_extra)); + srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra, (uint32_t)sizeof(str_extra)); INFO("PDSCH: %s\n%s", str, str_extra); } diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 7097127d0..3a899cb74 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -276,7 +276,7 @@ bool cc_worker::work_dl() if (logger.debug.enabled()) { str_extra_t str_extra; - srsran_phch_cfg_nr_info(&pdsch_cfg, str_extra.data(), (uint32_t)str_extra.size()); + srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra.data(), (uint32_t)str_extra.size()); logger.info(pdsch_res.tb[0].payload, pdsch_cfg.grant.tb[0].tbs / 8, "PDSCH: cc=%d, %s\n%s", @@ -392,7 +392,7 @@ bool cc_worker::work_ul() } // Set UCI configuration following procedures - srsran_ra_ul_set_grant_uci_nr(&phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); + srsran_ra_ul_set_grant_uci_nr(&phy->carrier, &phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); // Assigning MAC provided values to PUSCH config structs pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer; @@ -415,7 +415,7 @@ bool cc_worker::work_ul() if (logger.debug.enabled()) { str_extra_t str_extra; - srsran_phch_cfg_nr_info(&pusch_cfg, str_extra.data(), (uint32_t)str_extra.size()); + srsran_sch_cfg_nr_info(&pusch_cfg, str_extra.data(), (uint32_t)str_extra.size()); logger.info(ul_action.tb.payload->msg, pusch_cfg.grant.tb[0].tbs / 8, "PUSCH: cc=%d %s tti_tx=%d\n%s",