From 9dffad87f215534524d4cb1d3b72dacea7949573 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 3 Mar 2021 19:54:55 +0100 Subject: [PATCH] Initial UCI bits multiplexing in PUSCH --- lib/include/srslte/phy/phch/csi.h | 8 + lib/include/srslte/phy/phch/csi_cfg.h | 1 + lib/include/srslte/phy/phch/phch_cfg_nr.h | 1 + lib/include/srslte/phy/phch/pusch_nr.h | 13 +- lib/include/srslte/phy/phch/ra_ul_nr.h | 2 +- lib/include/srslte/phy/phch/sch_nr.h | 8 +- lib/include/srslte/phy/phch/uci_cfg_nr.h | 49 ++- lib/include/srslte/phy/phch/uci_nr.h | 18 +- lib/src/phy/phch/csi.c | 14 + lib/src/phy/phch/pdsch_nr.c | 2 +- lib/src/phy/phch/pucch_nr.c | 2 +- lib/src/phy/phch/pusch_nr.c | 425 +++++++++++++++++++++- lib/src/phy/phch/ra_ul_nr.c | 18 +- lib/src/phy/phch/sch_nr.c | 12 +- lib/src/phy/phch/test/pusch_nr_test.c | 72 ++-- lib/src/phy/phch/uci_nr.c | 121 ++---- lib/src/phy/ue/ue_dl_nr.c | 4 +- srsue/hdr/phy/nr/state.h | 14 +- 18 files changed, 605 insertions(+), 179 deletions(-) diff --git a/lib/include/srslte/phy/phch/csi.h b/lib/include/srslte/phy/phch/csi.h index 240097a8c..3f971eec7 100644 --- a/lib/include/srslte/phy/phch/csi.h +++ b/lib/include/srslte/phy/phch/csi.h @@ -37,6 +37,14 @@ SRSLTE_API int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, */ SRSLTE_API int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports); +/** + * @brief Checks if the report list contains part 2 CSI report + * @param report_list Report list + * @param nof_reports Number of reports in the list + * @return True if at least one report contains part 2, false otherwise + */ +SRSLTE_API bool srslte_csi_has_part2(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports); + /** * @brief Pack CSI part 1 bits for a PUCCH transmission * @param report_list Provides the CSI report list diff --git a/lib/include/srslte/phy/phch/csi_cfg.h b/lib/include/srslte/phy/phch/csi_cfg.h index 48a33699b..f6c578525 100644 --- a/lib/include/srslte/phy/phch/csi_cfg.h +++ b/lib/include/srslte/phy/phch/csi_cfg.h @@ -130,6 +130,7 @@ typedef struct SRSLTE_API { // Resource set context uint32_t nof_ports; ///< Number of antenna ports uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set + bool has_part2; ///< Set to true if the report has part 2 } srslte_csi_report_cfg_t; /** diff --git a/lib/include/srslte/phy/phch/phch_cfg_nr.h b/lib/include/srslte/phy/phch/phch_cfg_nr.h index 79a74069f..f694eb80f 100644 --- a/lib/include/srslte/phy/phch/phch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/phch_cfg_nr.h @@ -208,6 +208,7 @@ typedef struct SRSLTE_API { float beta_harq_ack_offset; float beta_csi_part1_offset; float scaling; + bool freq_hopping_enabled; } srslte_sch_cfg_nr_t; #endif // SRSLTE_PHCH_CFG_NR_H diff --git a/lib/include/srslte/phy/phch/pusch_nr.h b/lib/include/srslte/phy/phch/pusch_nr.h index 74d32b586..629e6464d 100644 --- a/lib/include/srslte/phy/phch/pusch_nr.h +++ b/lib/include/srslte/phy/phch/pusch_nr.h @@ -50,8 +50,17 @@ typedef struct SRSLTE_API { srslte_evm_buffer_t* evm_buffer; bool meas_time_en; uint32_t meas_time_us; - uint8_t* uci_ack; - uint8_t* uci_csi; + 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 + uint8_t* g_csi2; ///< Temporal Encoded CSI part 2 bits + uint32_t* pos_ulsch; ///< Reserved resource elements for HARQ-ACK multiplexing position + uint32_t* pos_ack; ///< Reserved resource elements for HARQ-ACK multiplexing position + uint32_t* pos_csi1; ///< Reserved resource elements for CSI part 1 multiplexing position + uint32_t* pos_csi2; ///< Reserved resource elements for CSI part 1 multiplexing position + uint32_t G_ack; ///< Number of encoded HARQ-ACK bits + uint32_t G_csi1; ///< Number of encoded CSI part 1 bits + uint32_t G_csi2; ///< Number of encoded CSI part 2 bits } srslte_pusch_nr_t; /** diff --git a/lib/include/srslte/phy/phch/ra_ul_nr.h b/lib/include/srslte/phy/phch/ra_ul_nr.h index 6b4ec57da..346ca91ed 100644 --- a/lib/include/srslte/phy/phch/ra_ul_nr.h +++ b/lib/include/srslte/phy/phch/ra_ul_nr.h @@ -52,7 +52,7 @@ SRSLTE_API int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code */ SRSLTE_API int -srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant); +srslte_ra_ul_nr_pusch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant); /** * @brief Calculates the number of PUSCH-DMRS CDM groups without data for DCI format 0_0 diff --git a/lib/include/srslte/phy/phch/sch_nr.h b/lib/include/srslte/phy/phch/sch_nr.h index 1772ea9ad..649e4de9f 100644 --- a/lib/include/srslte/phy/phch/sch_nr.h +++ b/lib/include/srslte/phy/phch/sch_nr.h @@ -107,10 +107,10 @@ SRSLTE_API srslte_basegraph_t srslte_sch_nr_select_basegraph(uint32_t tbs, doubl * @param cfg SCH object * @return */ -SRSLTE_API int srslte_sch_nr_fill_cfg(const srslte_carrier_nr_t* carrier, - const srslte_sch_cfg_t* sch_cfg, - const srslte_sch_tb_t* tb, - srslte_sch_nr_tb_info_t* cfg); +SRSLTE_API int srslte_sch_nr_fill_tb_info(const srslte_carrier_nr_t* carrier, + const srslte_sch_cfg_t* sch_cfg, + const srslte_sch_tb_t* tb, + srslte_sch_nr_tb_info_t* cfg); /** * @brief Initialises an SCH object as transmitter diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index 1408e0897..95f2e856c 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -14,7 +14,7 @@ #define SRSLTE_UCI_CFG_NR_H #include "csi_cfg.h" -#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/phy_common_nr.h" #include #include @@ -35,6 +35,37 @@ */ #define SRSLTE_UCI_NR_MAX_CSI1_BITS 10 +/** + * @brief Uplink Control Information bits configuration for PUCCH transmission + */ +typedef struct { + uint16_t rnti; ///< RNTI + uint32_t resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 + uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception + uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1 + uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR + bool sr_positive_present; ///< Set to true if there is at least one positive SR +} srslte_uci_nr_pucch_cfg_t; + +/** + * @brief Uplink Control Information bits configuration for PUSCH transmission + */ +typedef struct { + uint32_t l0; ///< First OFDM symbol that does not carry DMRS of the PUSCH, after the first DMRS symbol(s) + uint32_t l1; ///< OFDM symbol index of the first OFDM symbol that does not carry DMRS + uint32_t M_pusch_sc[SRSLTE_NSYMB_PER_SLOT_NR]; ///< Number of potential RE for PUSCH transmission + uint32_t M_pusch_sc_acc[SRSLTE_NSYMB_PER_SLOT_NR]; ///< Number of potential RE for PUSCH before the symbol + uint32_t M_uci_sc[SRSLTE_NSYMB_PER_SLOT_NR]; ///< Number of potential RE for UCI transmission + uint32_t K_sum; ///< Sum of UL-SCH code block sizes, set to zero if no UL-SCH + srslte_mod_t modulation; ///< Modulation for the PUSCH + uint32_t nof_layers; ///< Number of layers for PUSCH + float R; ///< Code rate of the PUSCH + float alpha; ///< Higher layer parameter scaling + float beta_harq_ack_offset; + float beta_csi_part1_offset; + uint32_t nof_re; +} srslte_uci_nr_pusch_cfg_t; + /** * @brief Uplink Control Information (UCI) message configuration */ @@ -44,18 +75,10 @@ typedef struct SRSLTE_API { uint32_t o_sr; ///< Number of SR bits srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration uint32_t nof_csi; ///< Number of CSI reports - - /// PUSCH only parameters - bool without_ul_sch; ///< Set to true if no UL-SCH data is scheduled - bool has_csi_part2; ///< Set to true if the CSI reports have part 2 - - /// PUCCH only parameters - uint16_t rnti; ///< RNTI - uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 - uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception - uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1 - uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR - bool sr_positive_present; ///< Set to true if there is at least one positive SR + union { + srslte_uci_nr_pucch_cfg_t pucch; ///< Configuration for transmission in PUCCH + srslte_uci_nr_pusch_cfg_t pusch; ///< Configuration for transmission in PUSCH + }; } srslte_uci_cfg_nr_t; /** diff --git a/lib/include/srslte/phy/phch/uci_nr.h b/lib/include/srslte/phy/phch/uci_nr.h index c98b7a82b..f3f93d796 100644 --- a/lib/include/srslte/phy/phch/uci_nr.h +++ b/lib/include/srslte/phy/phch/uci_nr.h @@ -125,23 +125,33 @@ SRSLTE_API int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q, srslte_uci_value_nr_t* value); /** - * @brief Calculates the total number of encoded bits for HARQ-ACK + * @brief Calculates total number of resource elements for HARQ-ACK multiplexing in PUSCH + * @remark Implementation according to TS 38.312 clause 6.3.2.4.1.1 for UCI encoded by polar code + * @remark Implementation according to TS 38.312 clause 6.3.2.4.2.1 for UCI encoded by channel codig of small lengths + * @param cfg UCI NR PUSCH configuration + * @param O_ack Number of ACK + * @return The number of resource elements for HARQ-ACK in a PUSCH transmission + */ +SRSLTE_API int srslte_uci_nr_pusch_ack_nof_re(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack); + +/** + * @brief Calculates total number of ebncoded bits for HARQ-ACK multiplexing in PUSCH * @param[in,out] q NR-UCI object * @param[in] cfg PUSCH transmission configuration * @return The number of encoded bits if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_uci_nr_pusch_E_uci_ack(srslte_uci_nr_t* q, const srslte_sch_cfg_nr_t* cfg); +SRSLTE_API int srslte_uci_nr_pusch_ack_nof_bits(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack); /** * @brief Encodes HARQ-ACK bits for PUSCH transmission * @param[in,out] q NR-UCI object - * @param[in] cfg PUSCH transmission configuration + * @param[in] cfg UCI configuration * @param[in] value UCI value * @param[out] o_ack Encoded ack bits * @return The number of encoded bits if successful, SRSLTE_ERROR code otherwise */ SRSLTE_API int srslte_uci_nr_encode_pusch_ack(srslte_uci_nr_t* q, - const srslte_sch_cfg_nr_t* cfg, + const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* o_ack); diff --git a/lib/src/phy/phch/csi.c b/lib/src/phy/phch/csi.c index 7b426da71..d6c7813e9 100644 --- a/lib/src/phy/phch/csi.c +++ b/lib/src/phy/phch/csi.c @@ -172,6 +172,20 @@ int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof return (int)count; } +bool srslte_csi_has_part2(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports) +{ + if (report_list == NULL || nof_reports == 0) { + return false; + } + + for (uint32_t i = 0; i < nof_reports; i++) { + if (report_list[i].has_part2) { + return true; + } + } + return false; +} + int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, const srslte_csi_report_value_t* report_value, uint32_t nof_reports, diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index 8ad4b2499..b7ee4dc0d 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -194,7 +194,7 @@ static void srslte_pdsch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count, * As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2: * * +---+---+---+---+---+---+---+---+---+---+---+---+ - * | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | + * | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | * +---+---+---+---+---+---+---+---+---+---+---+---+ * -- k --> * diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 92e4b9d51..30950cc96 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -538,7 +538,7 @@ static uint32_t pucch_nr_format2_cinit(const srslte_carrier_nr_t* carri { uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->id; - return ((uint32_t)uci_cfg->rnti << 15U) + n_id; + return ((uint32_t)uci_cfg->pucch.rnti << 15U) + n_id; } // Implements TS 38.211 section 6.3.2.5 PUCCH format 2 diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index 858f3124c..130fd8fc2 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -33,6 +33,24 @@ int pusch_nr_init_common(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* arg return SRSLTE_ERROR; } + q->g_ulsch = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->g_ack = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->g_csi1 = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->g_csi2 = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + if (q->g_ack == NULL || q->g_csi1 == NULL || q->g_csi2 == NULL || q->g_ulsch == NULL) { + ERROR("Malloc"); + return SRSLTE_ERROR; + } + + q->pos_ulsch = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->pos_ack = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->pos_csi1 = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + q->pos_csi2 = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR); + if (q->pos_ack == NULL || q->pos_csi1 == NULL || q->pos_csi2 == NULL || q->pos_ulsch == NULL) { + ERROR("Malloc"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } @@ -151,6 +169,32 @@ void srslte_pusch_nr_free(srslte_pusch_nr_t* q) return; } + if (q->g_ulsch != NULL) { + free(q->g_ulsch); + } + if (q->g_ack != NULL) { + free(q->g_ack); + } + if (q->g_csi1 != NULL) { + free(q->g_csi1); + } + if (q->g_csi2 != NULL) { + free(q->g_csi2); + } + + if (q->pos_ulsch != NULL) { + free(q->pos_ulsch); + } + if (q->pos_ack != NULL) { + free(q->pos_ack); + } + if (q->pos_csi1 != NULL) { + free(q->pos_csi1); + } + if (q->pos_csi2 != NULL) { + free(q->pos_csi2); + } + for (uint32_t cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { if (q->b[cw]) { free(q->b[cw]); @@ -176,6 +220,8 @@ void srslte_pusch_nr_free(srslte_pusch_nr_t* q) if (q->evm_buffer != NULL) { srslte_evm_free(q->evm_buffer); } + + SRSLTE_MEM_ZERO(q, srslte_pusch_nr_t, 1); } /** @@ -420,13 +466,302 @@ pusch_nr_cinit(const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_nr_t* cf return cinit; } -// int pusch_nr_mux_uci(srslte_pusch_nr_t* q) { -// uint8_t *g_ul_sch; // coded bits for UL-SCH -// uint8_t *g_ack; // coded bits for HARQ-ACK -// uint8_t *g_csi_p1; // coded bits for CSI part 1 -// uint8_t *g_csi_p2; // coded bits for CSI part 2 -// -//} +static inline int +pusch_nr_fill_uci_cfg(srslte_pusch_nr_t* q, const srslte_sch_cfg_nr_t* cfg, srslte_uci_cfg_nr_t* uci_cfg) +{ + // Initially, copy all fields + *uci_cfg = cfg->uci; + + // Reset UCI PUSCH configuration + SRSLTE_MEM_ZERO(&uci_cfg->pusch, srslte_uci_nr_pusch_cfg_t, 1); + + // Get DMRS symbol indexes + uint32_t nof_dmrs_l = 0; + uint32_t dmrs_l[SRSLTE_DMRS_SCH_MAX_SYMBOLS] = {}; + int n = srslte_dmrs_sch_get_symbols_idx(&cfg->dmrs, &cfg->grant, dmrs_l); + if (n < SRSLTE_SUCCESS) { + return SRSLTE_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 + 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]) { + 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 + int n_prb_dmrs = srslte_dmrs_sch_get_N_prb(&cfg->dmrs, &cfg->grant); + if (n_prb_dmrs < SRSLTE_SUCCESS) { + ERROR("Error calculating number of DMRS per PRB"); + return SRSLTE_ERROR; + } + + // Accumulative Resource Element shall start in zero + uci_cfg->pusch.M_pusch_sc_acc[0] = 0; + + // 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 < SRSLTE_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) || l == dmrs_l[dmrs_l_idx]) { + uci_cfg->pusch.M_pusch_sc[l] = 0; + uci_cfg->pusch.M_pusch_sc_acc[l + 1] = uci_cfg->pusch.M_pusch_sc_acc[l] + uci_cfg->pusch.M_pusch_sc[l]; + uci_cfg->pusch.M_uci_sc[l] = 0; + continue; + } + + // OFDM symbol carries DMRS + if (l == dmrs_l[dmrs_l_idx]) { + // Calculate PUSCH RE candidates + uci_cfg->pusch.M_pusch_sc[l] = cfg->grant.nof_prb * (SRSLTE_NRE - n_prb_dmrs); + uci_cfg->pusch.M_pusch_sc_acc[l + 1] = uci_cfg->pusch.M_pusch_sc_acc[l] + uci_cfg->pusch.M_pusch_sc[l]; + + // The Number of RE candidates for UCI are 0 + 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 + uci_cfg->pusch.M_pusch_sc[l] = cfg->grant.nof_prb * SRSLTE_NRE; + + // Calculate the number of UCI candidates + uci_cfg->pusch.M_uci_sc[l] = uci_cfg->pusch.M_pusch_sc[l] - M_ptrs_sc; + } + + // Generate SCH Transport block information + srslte_sch_nr_tb_info_t sch_tb_info = {}; + if (srslte_sch_nr_fill_tb_info(&q->carrier, &cfg->sch_cfg, &cfg->grant.tb[0], &sch_tb_info) < SRSLTE_SUCCESS) { + ERROR("Generating TB info"); + return SRSLTE_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 + uci_cfg->pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0; + } + + // Set other PUSCH parameters + uci_cfg->pusch.modulation = cfg->grant.tb[0].mod; + uci_cfg->pusch.nof_layers = cfg->grant.nof_layers; + uci_cfg->pusch.R = (float)cfg->grant.tb[0].R; + uci_cfg->pusch.alpha = cfg->scaling; + uci_cfg->pusch.beta_harq_ack_offset = cfg->beta_harq_ack_offset; + uci_cfg->pusch.beta_csi_part1_offset = cfg->beta_csi_part1_offset; + uci_cfg->pusch.nof_re = cfg->grant.tb[0].nof_re; + + return SRSLTE_SUCCESS; +} + +#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN)) + +// Implements TS 38.212 6.2.7 Data and control multiplexing (for NR-PUSCH) +static int pusch_nr_gen_mux_uci(srslte_pusch_nr_t* q, const srslte_uci_cfg_nr_t* cfg) +{ + // Bit positions + uint32_t* pos_ulsch = q->pos_ulsch; // coded bits for UL-SCH + uint32_t* pos_ack = q->pos_ack; // coded bits for HARQ-ACK + uint32_t* pos_csi1 = q->pos_csi1; // coded bits for CSI part 1 + uint32_t* pos_csi2 = q->pos_csi2; // coded bits for CSI part 2 + + // Key OFDM symbol indexes + uint32_t l1 = + cfg->pusch.l0; // First OFDM symbol that does not carry DMRS of the PUSCH, after the first DMRS symbol(s) + uint32_t l1_csi = cfg->pusch.l1; // OFDM symbol index of the first OFDM symbol that does not carry DMRS + + // Number of UCI bits + uint32_t G_ack = q->G_ack; + uint32_t G_csi1 = q->G_csi1; + uint32_t G_csi2 = q->G_csi2; + + // Other... + uint32_t Nl = cfg->pusch.nof_layers; + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->pusch.modulation); + + // If 2 or less HARQ-ACK bits, use reserve + uint32_t G_ack_rvd = 0; + if (cfg->o_ack <= 2) { + G_ack_rvd = G_ack; + G_ack = 0; + } + + // Counters + uint32_t m_ack_count = 0; + uint32_t m_csi1_count = 0; + uint32_t m_csi2_count = 0; + uint32_t m_ulsch_count = 0; + uint32_t m_all_count = 0; + + for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) { + // Skip if symbol has potential for data + if (cfg->pusch.M_pusch_sc[l] == 0) { + continue; + } + + // Put UL-SCH only if this OFDM symbol has no potential for UCI + if (cfg->pusch.M_uci_sc[l] == 0) { + for (uint32_t i = 0; i < cfg->pusch.M_pusch_sc[l] * Qm * Nl; i++) { + pos_ulsch[m_ulsch_count++] = m_all_count++; + } + continue; + } + + uint32_t M_ulsch_sc = cfg->pusch.M_pusch_sc[l]; + uint32_t M_uci_sc = cfg->pusch.M_uci_sc[l]; + uint32_t M_uci_rvd = 0; + + // Compute HARQ-ACK bits multiplexing + uint32_t ack_d = 0; + uint32_t ack_m_re_count = 0; + if (l >= l1 && m_ack_count < G_ack_rvd) { + if (cfg->o_ack <= 2) { + ack_d = 1; + ack_m_re_count = M_ulsch_sc; + if (G_ack_rvd - m_ack_count < M_uci_sc * Nl * Qm) { + ack_d = (M_uci_sc * Nl * Qm) / (G_ack_rvd - m_ack_count); + ack_m_re_count = CEIL(G_ack_rvd - m_ack_count, Nl * Qm); + } + M_uci_rvd = ack_m_re_count; + } else { + ack_d = 1; + ack_m_re_count = M_ulsch_sc; + if (G_ack - m_ack_count < M_uci_sc * Nl * Qm) { + ack_d = (M_uci_sc * Nl * Qm) / (G_ack_rvd - m_ack_count); + ack_m_re_count = M_ulsch_sc; + } + M_uci_sc -= ack_m_re_count; + } + } + + // Compute CSI part 1 bits multiplexing + uint32_t csi1_d = 0; + uint32_t csi1_m_re_count = 0; + if (l >= l1_csi && M_uci_sc > M_uci_rvd && m_csi1_count < G_csi1) { + csi1_d = 1; + csi1_m_re_count = M_uci_sc - M_uci_rvd; + if (G_csi1 - m_csi1_count < (M_uci_sc - M_uci_rvd) * Nl * Qm) { + csi1_d = ((M_uci_sc - M_uci_rvd) * Nl * Qm) / (G_csi1 - m_csi1_count); + csi1_m_re_count = CEIL(G_csi1 - m_csi1_count, Nl * Qm); + } + M_uci_sc -= csi1_m_re_count; + } + + // Compute CSI part 2 bits multiplexing + uint32_t csi2_d = 0; + uint32_t csi2_m_re_count = 0; + if (l >= l1_csi && M_uci_sc > M_uci_rvd && m_csi2_count < G_csi2) { + csi2_d = 1; + csi2_m_re_count = M_uci_sc - M_uci_rvd; + if (G_csi2 - m_csi2_count < (M_uci_sc - M_uci_rvd) * Nl * Qm) { + csi2_d = ((M_uci_sc - M_uci_rvd) * Nl * Qm) / (G_csi2 - m_csi2_count); + csi2_m_re_count = CEIL(G_csi2 - m_csi2_count, Nl * Qm); + } + M_uci_sc -= csi2_m_re_count; + } + + // Leave the rest for UL-SCH + uint32_t ulsch_m_re_count = M_uci_sc; + + for (uint32_t i = 0, csi1_i = 0, csi2_i = 0; i < cfg->pusch.M_pusch_sc[l] * Qm * Nl; i++) { + if (ack_m_re_count != 0 && i % ack_d == 0 && m_ack_count < G_ack) { + for (uint32_t j = 0; j < Nl * Qm; j++) { + pos_ack[m_ack_count++] = m_all_count++; + } + ack_m_re_count--; + } else if (csi1_m_re_count != 0 && csi1_i % csi1_d == 0 && m_csi1_count < G_csi1) { + for (uint32_t j = 0; j < Nl * Qm; j++) { + pos_csi1[m_csi1_count++] = m_all_count++; + } + csi1_m_re_count--; + csi1_i++; + } else if (csi2_m_re_count != 0 && csi2_i % csi2_d == 0 && m_csi2_count < G_csi2) { + for (uint32_t j = 0; j < Nl * Qm; j++) { + pos_csi2[m_csi2_count++] = m_all_count++; + } + csi2_m_re_count--; + csi1_i++; + csi2_i++; + } else { + for (uint32_t j = 0; j < Nl * Qm; j++) { + pos_ulsch[m_ulsch_count++] = m_all_count++; + } + ulsch_m_re_count--; + csi1_i++; + csi2_i++; + } + + // Set reserved bits + if (i % ack_d == 0 && m_ack_count < G_ack_rvd) { + for (uint32_t j = 0; j < Nl * Qm; j++) { + pos_ack[m_ack_count++] = m_all_count++; + } + ack_m_re_count--; + } + } + + // Checks that all RE are allocated as planned + if (ack_m_re_count != 0) { + ERROR("ack_m_re_count=%d", ack_m_re_count); + } + if (csi1_m_re_count != 0) { + ERROR("csi1_m_re_count=%d", csi1_m_re_count); + } + if (csi2_m_re_count != 0) { + ERROR("csi2_m_re_count=%d", csi2_m_re_count); + } + if (ulsch_m_re_count != 0) { + ERROR("ulsch_m_re_count=%d", ulsch_m_re_count); + } + } + + if (G_ack_rvd != 0 && G_ack_rvd != m_ack_count) { + ERROR("Not matched %d!=%d", G_ack_rvd, m_ack_count); + } + if (G_ack != 0 && G_ack != m_ack_count) { + ERROR("Not matched %d!=%d", G_ack, m_ack_count); + } + if (G_csi1 != 0 && G_csi1 != m_csi1_count) { + ERROR("Not matched %d!=%d", G_csi1, m_csi1_count); + } + if (G_csi2 != 0 && G_csi2 != m_csi2_count) { + ERROR("Not matched %d!=%d", G_csi2, m_csi2_count); + } + + return SRSLTE_SUCCESS; +} static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q, const srslte_sch_cfg_nr_t* cfg, @@ -453,7 +788,7 @@ static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q, } // Encode SCH - if (srslte_ulsch_nr_encode(&q->sch, &cfg->sch_cfg, tb, data, q->b[tb->cw_idx]) < SRSLTE_SUCCESS) { + if (srslte_ulsch_nr_encode(&q->sch, &cfg->sch_cfg, tb, data, q->g_ulsch) < SRSLTE_SUCCESS) { ERROR("Error in SCH encoding"); return SRSLTE_ERROR; } @@ -463,6 +798,30 @@ static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q, srslte_vec_fprint_b(stdout, q->b[tb->cw_idx], tb->nof_bits); } + // Multiplex UL-SCH + for (uint32_t i = 0; i < tb->nof_bits; i++) { + q->b[tb->cw_idx][q->pos_ulsch[i]] = q->g_ulsch[i]; + } + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { + DEBUG("UL-SCH bit positions:"); + srslte_vec_fprint_i(stdout, (int*)q->pos_ulsch, tb->nof_bits); + } + + // Multiplex CSI part 1 + for (uint32_t i = 0; i < q->G_csi1; i++) { + q->b[tb->cw_idx][q->pos_csi1[i]] = q->g_csi1[i]; + } + + // Multiplex CSI part 2 + for (uint32_t i = 0; i < q->G_csi2; i++) { + q->b[tb->cw_idx][q->pos_csi2[i]] = q->g_csi2[i]; + } + + // Multiplex HARQ-ACK + for (uint32_t i = 0; i < q->G_ack; i++) { + q->b[tb->cw_idx][q->pos_ack[i]] = q->g_ack[i]; + } + // 7.3.1.1 Scrambling uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx); srslte_sequence_apply_bit(q->b[tb->cw_idx], q->b[tb->cw_idx], tb->nof_bits, cinit); @@ -500,12 +859,26 @@ int srslte_pusch_nr_encode(srslte_pusch_nr_t* q, return SRSLTE_ERROR; } + // Fill UCI configuration for PUSCH configuration + srslte_uci_cfg_nr_t uci_cfg = {}; + if (pusch_nr_fill_uci_cfg(q, cfg, &uci_cfg) < SRSLTE_SUCCESS) { + ERROR("Error filling UCI configuration for PUSCH"); + return SRSLTE_ERROR; + } + // Encode HARQ-ACK bits - int E_uci_ack = srslte_uci_nr_encode_pusch_ack(&q->uci, cfg, &data[0].uci, q->uci_ack); + int E_uci_ack = srslte_uci_nr_encode_pusch_ack(&q->uci, &uci_cfg, &data[0].uci, q->g_ack); if (E_uci_ack < SRSLTE_SUCCESS) { ERROR("Error encoding HARQ-ACK bits"); return SRSLTE_ERROR; } + q->G_ack = E_uci_ack; + + // Generate PUSCH UCI/UL-SCH multiplexing + if (pusch_nr_gen_mux_uci(q, &uci_cfg) < SRSLTE_SUCCESS) { + ERROR("Error generating PUSCH mux tables"); + return SRSLTE_ERROR; + } // 7.3.1.1 and 7.3.1.2 uint32_t nof_cw = 0; @@ -592,21 +965,26 @@ static inline int pusch_nr_decode_codeword(srslte_pusch_nr_t* q, res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits); } - // Change LLR sign + // Demultiplex UL-SCH, change sign + int8_t* g_ulsch_llr = (int8_t*)q->g_ulsch; for (uint32_t i = 0; i < tb->nof_bits; i++) { - llr[i] = -llr[i]; + g_ulsch_llr[i] = -llr[q->pos_ulsch[i]]; + } + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { + DEBUG("UL-SCH bit positions:"); + srslte_vec_fprint_i(stdout, (int*)q->pos_ulsch, tb->nof_bits); } // Descrambling - srslte_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); + srslte_sequence_apply_c(g_ulsch_llr, g_ulsch_llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { DEBUG("b="); - srslte_vec_fprint_b(stdout, q->b[tb->cw_idx], tb->nof_bits); + srslte_vec_fprint_bs(stdout, g_ulsch_llr, tb->nof_bits); } // Decode SCH - if (srslte_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSLTE_SUCCESS) { + if (srslte_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, g_ulsch_llr, res->payload, &res->crc) < SRSLTE_SUCCESS) { ERROR("Error in SCH decoding"); return SRSLTE_ERROR; } @@ -631,6 +1009,25 @@ int srslte_pusch_nr_decode(srslte_pusch_nr_t* q, gettimeofday(&t[1], NULL); } + // Check number of layers + if (q->max_layers < grant->nof_layers) { + ERROR("Error number of layers (%d) exceeds configured maximum (%d)", grant->nof_layers, q->max_layers); + return SRSLTE_ERROR; + } + + // Fill UCI configuration for PUSCH configuration + srslte_uci_cfg_nr_t uci_cfg = {}; + if (pusch_nr_fill_uci_cfg(q, cfg, &uci_cfg) < SRSLTE_SUCCESS) { + ERROR("Error filling UCI configuration for PUSCH"); + return SRSLTE_ERROR; + } + + // Generate PUSCH UCI/UL-SCH multiplexing + if (pusch_nr_gen_mux_uci(q, &uci_cfg) < SRSLTE_SUCCESS) { + ERROR("Error generating PUSCH mux tables"); + return SRSLTE_ERROR; + } + uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { nof_cw += grant->tb[tb].enabled ? 1 : 0; diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 8663245f3..e78ca4d2e 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -42,7 +42,7 @@ static const ue_ra_time_resource_t ue_ul_default_A_lut[16] = {{srslte_sch_mappin {srslte_sch_mapping_type_A, 3, 0, 14}, {srslte_sch_mapping_type_A, 3, 0, 10}}; -int srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant) +int srslte_ra_ul_nr_pusch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant) { uint32_t j[4] = {1, 1, 2, 3}; @@ -141,7 +141,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, if (ss_type == srslte_search_space_type_rar) { // Row 1 if (cfg->nof_common_time_ra == 0) { - srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant); } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION && m < cfg->nof_common_time_ra) { ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); } else { @@ -154,7 +154,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id == 0) { // Row 2 if (cfg->nof_common_time_ra == 0) { - srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant); } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION) { ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); } @@ -168,7 +168,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, } else if (cfg->nof_common_time_ra > 0) { ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); } else { - srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant); } } else { ERROR("Unhandled case"); @@ -461,9 +461,9 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, // - At least one positive SR // - up to 2 HARQ-ACK // - No CSI report - if (uci_cfg->sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && + if (uci_cfg->pucch.sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { - uint32_t sr_resource_id = uci_cfg->sr_resource_id; + uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id; if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) { ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES); return SRSLTE_ERROR; @@ -486,7 +486,7 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, // - More than 2 HARQ-ACK // - No CSI report if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { - return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); + return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource); } // Use format 2, 3 or 4 CSI report resource from higher layers @@ -502,10 +502,10 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, // a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size // transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs. if (!pucch_cfg->enabled) { - uint32_t r_pucch = (2 * uci_cfg->n_cce_0) + 2 * uci_cfg->pucch_resource_id; + uint32_t r_pucch = (2 * uci_cfg->pucch.n_cce_0) + 2 * uci_cfg->pucch.resource_id; return ra_ul_nr_pucch_resource_default(r_pucch, resource); } - return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); + return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource); } uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K) diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index 794cc855f..becba1cd5 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -65,10 +65,10 @@ uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb) return 273; } -int srslte_sch_nr_fill_cfg(const srslte_carrier_nr_t* carrier, - const srslte_sch_cfg_t* sch_cfg, - const srslte_sch_tb_t* tb, - srslte_sch_nr_tb_info_t* cfg) +int srslte_sch_nr_fill_tb_info(const srslte_carrier_nr_t* carrier, + const srslte_sch_cfg_t* sch_cfg, + const srslte_sch_tb_t* tb, + srslte_sch_nr_tb_info_t* cfg) { if (!sch_cfg || !tb || !cfg) { return SRSLTE_ERROR_INVALID_INPUTS; @@ -372,7 +372,7 @@ static inline int sch_nr_encode(srslte_sch_nr_t* q, uint8_t* output_ptr = e_bits; srslte_sch_nr_tb_info_t cfg = {}; - if (srslte_sch_nr_fill_cfg(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { + if (srslte_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } @@ -514,7 +514,7 @@ int sch_nr_decode(srslte_sch_nr_t* q, int8_t* input_ptr = e_bits; srslte_sch_nr_tb_info_t cfg = {}; - if (srslte_sch_nr_fill_cfg(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { + if (srslte_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index 581b3752f..a123612f1 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -27,13 +27,12 @@ static srslte_carrier_nr_t carrier = { 1 // max_mimo_layers }; -static uint32_t n_prb = 0; // Set to 0 for steering -static uint32_t mcs = 30; // Set to 30 for steering -static srslte_sch_cfg_nr_t pusch_cfg = {}; -static srslte_sch_grant_nr_t pusch_grant = {}; -static uint16_t rnti = 0x1234; -static uint32_t nof_ack_bits = 0; -static uint32_t nof_csi_bits = 0; +static uint32_t n_prb = 0; // Set to 0 for steering +static uint32_t mcs = 30; // Set to 30 for steering +static srslte_sch_cfg_nr_t pusch_cfg = {}; +static uint16_t rnti = 0x1234; +static uint32_t nof_ack_bits = 0; +static uint32_t nof_csi_bits = 0; void usage(char* prog) { @@ -159,20 +158,20 @@ int main(int argc, char** argv) } // Use grant default A time resources with m=0 - if (srslte_ra_ul_nr_pdsch_time_resource_default_A(carrier.numerology, 0, &pusch_grant) < SRSLTE_SUCCESS) { + if (srslte_ra_ul_nr_pusch_time_resource_default_A(carrier.numerology, 0, &pusch_cfg.grant) < SRSLTE_SUCCESS) { ERROR("Error loading default grant"); goto clean_exit; } // Load number of DMRS CDM groups without data - if (srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_grant) < SRSLTE_SUCCESS) { + if (srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_cfg.grant) < SRSLTE_SUCCESS) { ERROR("Error loading number of DMRS CDM groups without data"); goto clean_exit; } - pusch_grant.nof_layers = carrier.max_mimo_layers; - pusch_grant.dci_format = srslte_dci_format_nr_1_0; - pusch_grant.rnti = rnti; + pusch_cfg.grant.nof_layers = carrier.max_mimo_layers; + pusch_cfg.grant.dci_format = srslte_dci_format_nr_1_0; + pusch_cfg.grant.rnti = rnti; uint32_t n_prb_start = 1; uint32_t n_prb_end = carrier.nof_prb + 1; @@ -188,6 +187,10 @@ int main(int argc, char** argv) mcs_end = SRSLTE_MIN(mcs + 1, mcs_end); } + pusch_cfg.scaling = 0.650f; + pusch_cfg.beta_harq_ack_offset = 5.000f; + pusch_cfg.beta_csi_part1_offset = 5.000f; + if (srslte_chest_dl_res_init(&chest, carrier.nof_prb) < SRSLTE_SUCCESS) { ERROR("Initiating chest"); goto clean_exit; @@ -196,11 +199,11 @@ int main(int argc, char** argv) for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { for (mcs = mcs_start; mcs < mcs_end; mcs++) { for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { - pusch_grant.prb_idx[n] = (n < n_prb); + pusch_cfg.grant.prb_idx[n] = (n < n_prb); } - pusch_grant.dci_format = srslte_dci_format_nr_0_0; - if (srslte_ra_nr_fill_tb(&pusch_cfg, &pusch_grant, mcs, &pusch_grant.tb[0]) < SRSLTE_SUCCESS) { + pusch_cfg.grant.dci_format = srslte_dci_format_nr_0_0; + if (srslte_ra_nr_fill_tb(&pusch_cfg, &pusch_cfg.grant, mcs, &pusch_cfg.grant.tb[0]) < SRSLTE_SUCCESS) { ERROR("Error filing tb"); goto clean_exit; } @@ -212,10 +215,10 @@ int main(int argc, char** argv) continue; } - for (uint32_t i = 0; i < pusch_grant.tb[tb].tbs; i++) { + for (uint32_t i = 0; i < pusch_cfg.grant.tb[tb].tbs; i++) { data_tx[tb].payload[i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); } - pusch_grant.tb[tb].softbuffer.tx = &softbuffer_tx; + pusch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx; } // Generate HARQ ACK bits @@ -238,22 +241,23 @@ int main(int argc, char** argv) } } - if (srslte_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_grant, data_tx, sf_symbols) < SRSLTE_SUCCESS) { + if (srslte_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, data_tx, sf_symbols) < SRSLTE_SUCCESS) { ERROR("Error encoding"); goto clean_exit; } for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - pusch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; - srslte_softbuffer_rx_reset(pusch_grant.tb[tb].softbuffer.rx); + pusch_cfg.grant.tb[tb].softbuffer.rx = &softbuffer_rx; + srslte_softbuffer_rx_reset(pusch_cfg.grant.tb[tb].softbuffer.rx); } - for (uint32_t i = 0; i < pusch_grant.tb->nof_re; i++) { + for (uint32_t i = 0; i < pusch_cfg.grant.tb->nof_re; i++) { chest.ce[0][0][i] = 1.0f; } - chest.nof_re = pusch_grant.tb->nof_re; + chest.nof_re = pusch_cfg.grant.tb->nof_re; - if (srslte_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_grant, &chest, sf_symbols, data_rx) < SRSLTE_SUCCESS) { + if (srslte_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, data_rx) < + SRSLTE_SUCCESS) { ERROR("Error encoding"); goto clean_exit; } @@ -264,18 +268,18 @@ int main(int argc, char** argv) } float mse = 0.0f; - uint32_t nof_re = srslte_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_grant); - for (uint32_t i = 0; i < pusch_grant.nof_layers; i++) { + uint32_t nof_re = srslte_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_cfg.grant); + for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) { for (uint32_t j = 0; j < nof_re; j++) { mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]); } } - if (nof_re * pusch_grant.nof_layers > 0) { - mse = mse / (nof_re * pusch_grant.nof_layers); + if (nof_re * pusch_cfg.grant.nof_layers > 0) { + mse = mse / (nof_re * pusch_cfg.grant.nof_layers); } if (mse > 0.001) { ERROR("MSE error (%f) is too high", mse); - for (uint32_t i = 0; i < pusch_grant.nof_layers; i++) { + for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) { printf("d_tx[%d]=", i); srslte_vec_fprint_c(stdout, pusch_tx.d[i], nof_re); printf("d_rx[%d]=", i); @@ -285,20 +289,20 @@ int main(int argc, char** argv) } if (!data_rx[0].crc) { - ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_grant.tb[0].tbs); + ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs); goto clean_exit; } - if (memcmp(data_tx[0].payload, data_rx[0].payload, pusch_grant.tb[0].tbs / 8) != 0) { - ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_grant.tb[0].tbs); + if (memcmp(data_tx[0].payload, data_rx[0].payload, pusch_cfg.grant.tb[0].tbs / 8) != 0) { + ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs); printf("Tx data: "); - srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_grant.tb[0].tbs / 8); + srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8); printf("Rx data: "); - srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_grant.tb[0].tbs / 8); + srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8); goto clean_exit; } - printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_grant.tb[0].tbs, data_rx[0].evm); + printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx[0].evm); } } diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index 1a5c778b7..1e4ce8dc2 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -11,11 +11,9 @@ */ #include "srslte/phy/phch/uci_nr.h" -#include "srslte/phy/ch_estimation/dmrs_sch.h" #include "srslte/phy/fec/block/block.h" #include "srslte/phy/fec/polar/polar_chanalloc.h" #include "srslte/phy/phch/csi.h" -#include "srslte/phy/phch/sch_nr.h" #include "srslte/phy/phch/uci_cfg.h" #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/vector.h" @@ -258,13 +256,12 @@ static int uci_nr_unpack_pucch(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence return SRSLTE_ERROR; } -static int -uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, srslte_mod_t modulation, uint8_t* o, uint32_t E) +static int uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint8_t* o, uint32_t E) { uint32_t i = 0; srslte_uci_bit_type_t c0 = (q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1; - switch (modulation) { + switch (cfg->pusch.modulation) { case SRSLTE_MOD_BPSK: while (i < E) { o[i++] = c0; @@ -317,15 +314,14 @@ uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, srslte_mo return E; } -static int -uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, srslte_mod_t modulation, uint8_t* o, uint32_t E) +static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint8_t* o, uint32_t E) { uint32_t i = 0; srslte_uci_bit_type_t c0 = (q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1; srslte_uci_bit_type_t c1 = (q->bit_sequence[1] == 0) ? UCI_BIT_0 : UCI_BIT_1; srslte_uci_bit_type_t c2 = ((q->bit_sequence[0] ^ q->bit_sequence[1]) == 0) ? UCI_BIT_0 : UCI_BIT_1; - switch (modulation) { + switch (cfg->pusch.modulation) { case SRSLTE_MOD_BPSK: case SRSLTE_MOD_QPSK: while (i < E) { @@ -643,21 +639,16 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q, return SRSLTE_SUCCESS; } -static int uci_nr_encode(srslte_uci_nr_t* q, - const srslte_uci_cfg_nr_t* uci_cfg, - srslte_mod_t mod, - uint32_t A, - uint8_t* o, - uint32_t E_uci) +static int uci_nr_encode(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t A, uint8_t* o, uint32_t E_uci) { // 5.3.3.1 Encoding of 1-bit information if (A == 1) { - return uci_nr_encode_1bit(q, uci_cfg, mod, o, E_uci); + return uci_nr_encode_1bit(q, uci_cfg, o, E_uci); } // 5.3.3.2 Encoding of 2-bit information if (A == 2) { - return uci_nr_encode_2bit(q, uci_cfg, mod, o, E_uci); + return uci_nr_encode_2bit(q, uci_cfg, o, E_uci); } // 5.3.3.3 Encoding of other small block lengths @@ -781,7 +772,7 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q, return SRSLTE_ERROR; } - return uci_nr_encode(q, uci_cfg, SRSLTE_MOD_NITEMS, A, o, E_uci); + return uci_nr_encode(q, uci_cfg, A, o, E_uci); } int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q, @@ -816,7 +807,7 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin { uint32_t len = 0; - len = srslte_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.rnti); + len = srslte_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.pucch.rnti); if (uci_data->cfg.o_ack > 0) { char str2[10]; @@ -835,92 +826,59 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin return len; } -static int uci_nr_Q_ack_prime(srslte_uci_nr_t* q, const srslte_sch_cfg_nr_t* sch_cfg, uint32_t A) +int srslte_uci_nr_pusch_ack_nof_re(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack) { - // Get UL-SCH TB information - srslte_sch_nr_tb_info_t tb_info = {}; - if (srslte_sch_nr_fill_cfg(&q->carrier, &sch_cfg->sch_cfg, &sch_cfg->grant.tb[0], &tb_info) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - // Get DMRS symbol indexes - uint32_t nof_dmrs_l = 0; - uint32_t dmrs_l[SRSLTE_DMRS_SCH_MAX_SYMBOLS] = {}; - int n = srslte_dmrs_sch_get_symbols_idx(&sch_cfg->dmrs, &sch_cfg->grant, dmrs_l); - if (n < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; + if (cfg == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; } - nof_dmrs_l = (uint32_t)n; - uint32_t O_ack = A; // Number of HARQ-ACK bits - uint32_t L_ack = srslte_uci_nr_crc_len(A); // Number of CRC bits - float beta_pusch_offset = sch_cfg->beta_harq_ack_offset; // Beta offset given by higher layers - uint32_t C_ulsch = tb_info.C; // number of code blocks for UL-SCH of the PUSCH - float alpha = sch_cfg->scaling; // Higher layer parameter scaling - float R = (float)sch_cfg->grant.tb[0].R; // code rate of the PUSCH - float Qm = srslte_mod_bits_x_symbol(sch_cfg->grant.tb[0].mod); // modulation order of the PUSCH + uint32_t L_ack = srslte_uci_nr_crc_len(O_ack); // Number of CRC bits + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->modulation); // modulation order of the PUSCH - uint32_t K_sum = 0; - for (uint32_t i = 0; i < SRSLTE_MIN(C_ulsch, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC); i++) { - K_sum += tb_info.mask[i] ? 0 : tb_info.Kr; - } - - uint32_t dmrs_l_idx = 0; uint32_t M_uci_sum = 0; uint32_t M_uci_l0_sum = 0; - for (uint32_t l = sch_cfg->grant.S; l < sch_cfg->grant.S + sch_cfg->grant.L; l++) { - uint32_t M_ptrs_sc = 0; // Not implemented yet - uint32_t M_pusch_sc = sch_cfg->grant.nof_prb * SRSLTE_NRE; - uint32_t M_uci_sc = M_pusch_sc - M_ptrs_sc; - - // If the OFDM symbol contains DMRS, no UCI is mapped - if (l == dmrs_l[dmrs_l_idx] && dmrs_l_idx < nof_dmrs_l) { - M_uci_sc = 0; - dmrs_l_idx++; + for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) { + M_uci_sum += cfg->M_uci_sc[l]; + if (l >= cfg->l0) { + M_uci_l0_sum += cfg->M_uci_sc[l]; } + } - // Add subcarriers that can contain UCI RE - M_uci_sum += M_uci_sc; - - // Start adding after the first DMRS symbol - if (dmrs_l_idx > 0) { - M_uci_l0_sum += M_uci_sc; - } + if (!isnormal(cfg->R)) { + ERROR("Invalid Rate (%f)", cfg->R); + return SRSLTE_ERROR; } - if (sch_cfg->uci.without_ul_sch) { - return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * beta_pusch_offset) / (Qm * R)), alpha * M_uci_l0_sum); + if (cfg->K_sum == 0) { + return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * cfg->beta_harq_ack_offset) / (Qm * cfg->R)), + cfg->alpha * M_uci_l0_sum); } - return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * beta_pusch_offset * M_uci_sum) / (float)K_sum), alpha * M_uci_l0_sum); + return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * cfg->beta_harq_ack_offset * M_uci_sum) / cfg->K_sum), + cfg->alpha * M_uci_l0_sum); } -int srslte_uci_nr_pusch_E_uci_ack(srslte_uci_nr_t* q, const srslte_sch_cfg_nr_t* cfg) +int srslte_uci_nr_pusch_ack_nof_bits(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack) { - int A = cfg->uci.o_ack; - // Check inputs - if (q == NULL || cfg == NULL) { + if (cfg == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->uci.without_ul_sch && cfg->uci.nof_csi > 1 && !cfg->uci.has_csi_part2 && cfg->uci.o_ack < 2) { - A = 2; - } - - int Q_ack_prime = uci_nr_Q_ack_prime(q, cfg, A); + int Q_ack_prime = srslte_uci_nr_pusch_ack_nof_re(cfg, O_ack); if (Q_ack_prime < SRSLTE_SUCCESS) { + ERROR("Error calculating number of RE"); return Q_ack_prime; } - return (int)(Q_ack_prime * cfg->grant.nof_layers * srslte_mod_bits_x_symbol(cfg->grant.tb[0].mod)); + return (int)(Q_ack_prime * cfg->nof_layers * srslte_mod_bits_x_symbol(cfg->modulation)); } int srslte_uci_nr_encode_pusch_ack(srslte_uci_nr_t* q, - const srslte_sch_cfg_nr_t* cfg, + const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* o) { - int A = cfg->uci.o_ack; + int A = cfg->o_ack; // Check inputs if (q == NULL || cfg == NULL || value == NULL || o == NULL) { @@ -929,20 +887,21 @@ int srslte_uci_nr_encode_pusch_ack(srslte_uci_nr_t* q, // 6.3.2.1 UCI bit sequence generation // 6.3.2.1.1 HARQ-ACK - if (cfg->uci.without_ul_sch && cfg->uci.nof_csi > 1 && !cfg->uci.has_csi_part2 && cfg->uci.o_ack < 2) { + bool has_csi_part2 = srslte_csi_has_part2(cfg->csi, cfg->nof_csi); + if (cfg->pusch.K_sum == 0 && cfg->nof_csi > 1 && !has_csi_part2 && cfg->o_ack < 2) { A = 2; - q->bit_sequence[0] = (cfg->uci.o_ack == 0) ? 0 : value->ack[0]; + q->bit_sequence[0] = (cfg->o_ack == 0) ? 0 : value->ack[0]; q->bit_sequence[1] = 0; } else { - srslte_vec_u8_copy(q->bit_sequence, value->ack, cfg->uci.o_ack); + srslte_vec_u8_copy(q->bit_sequence, value->ack, cfg->o_ack); } // Compute total of encoded bits according to 6.3.2.4 Rate matching - int E_uci = srslte_uci_nr_pusch_E_uci_ack(q, cfg); + int E_uci = srslte_uci_nr_pusch_ack_nof_bits(&cfg->pusch, A); if (E_uci < SRSLTE_SUCCESS) { ERROR("Error calculating number of encoded bits"); return SRSLTE_ERROR; } - return uci_nr_encode(q, &cfg->uci, cfg->grant.tb[0].mod, A, o, E_uci); + return uci_nr_encode(q, cfg, A, o, E_uci); } \ No newline at end of file diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index 6367d5be3..dd253931b 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -574,8 +574,8 @@ static int ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, } else { if (ack->present) { // Load ACK resource data into UCI info - uci_data->cfg.pucch_resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id; - uci_data->cfg.rnti = ack_info->cc[c].m[m].resource.rnti; + uci_data->cfg.pucch.resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id; + uci_data->cfg.pucch.rnti = ack_info->cc[c].m[m].resource.rnti; if (V_DL_CDAI <= V_temp) { j = j + 1; diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 7db19bee2..ff379c16d 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -73,9 +73,9 @@ public: carrier.max_mimo_layers = 1; // Hard-coded values, this should be set when the measurements take place - csi_measurements[0].K_csi_rs = 1; + csi_measurements[0].K_csi_rs = 1; csi_measurements[0].nof_ports = 1; - csi_measurements[1].K_csi_rs = 4; + csi_measurements[1].K_csi_rs = 4; csi_measurements[0].nof_ports = 1; } @@ -294,10 +294,10 @@ public: } // Configure SR fields in UCI data - uci_data.cfg.sr_resource_id = sr_resource_id[0]; - uci_data.cfg.o_sr = srslte_ra_ul_nr_nof_sr_bits(sr_count_all); - uci_data.cfg.sr_positive_present = sr_count_positive > 0; - uci_data.value.sr = sr_count_positive; + uci_data.cfg.pucch.sr_resource_id = sr_resource_id[0]; + uci_data.cfg.o_sr = srslte_ra_ul_nr_nof_sr_bits(sr_count_all); + uci_data.cfg.pucch.sr_positive_present = sr_count_positive > 0; + uci_data.value.sr = sr_count_positive; } void get_periodic_csi(const uint32_t& tti, srslte_uci_data_nr_t& uci_data) @@ -307,7 +307,7 @@ public: uci_data.cfg.nof_csi = n; } - uci_data.cfg.rnti = stack->get_ul_sched_rnti_nr(tti).id; + uci_data.cfg.pucch.rnti = stack->get_ul_sched_rnti_nr(tti).id; } }; } // namespace nr