From 49731ab5a1029b9efa7708401960cf6f19844194 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 29 Mar 2021 18:10:43 +0200 Subject: [PATCH] Initial NR-DCI refactor Added NR DCI 1_1 size Several DCI NR fixes --- .../interfaces/rrc_nr_interface_types.h | 128 +- lib/include/srsran/phy/common/phy_common_nr.h | 33 +- lib/include/srsran/phy/enb/enb_dl_nr.h | 14 +- lib/include/srsran/phy/phch/dci_nr.h | 259 +++- lib/include/srsran/phy/phch/pdcch_cfg_nr.h | 44 + lib/include/srsran/phy/phch/phch_cfg_nr.h | 7 +- lib/include/srsran/phy/ue/ue_dl_nr.h | 55 +- lib/src/asn1/rrc_nr_utils.cc | 48 +- lib/src/phy/common/phy_common_nr.c | 30 + lib/src/phy/enb/enb_dl_nr.c | 32 +- lib/src/phy/phch/dci_nr.c | 1114 ++++++++++++----- lib/src/phy/phch/pdcch_nr.c | 28 +- lib/src/phy/phch/ra_dl_nr.c | 16 +- lib/src/phy/phch/ra_nr.c | 31 +- lib/src/phy/phch/ra_ul_nr.c | 12 +- lib/src/phy/phch/test/CMakeLists.txt | 4 + lib/src/phy/phch/test/dci_nr_test.c | 53 + lib/src/phy/phch/test/pdcch_nr_test.c | 41 +- lib/src/phy/ue/ue_dl_nr.c | 256 ++-- lib/test/asn1/rrc_nr_utils_test.cc | 2 +- lib/test/phy/phy_dl_nr_test.c | 38 +- srsenb/hdr/phy/nr/cc_worker.h | 13 +- srsenb/src/phy/nr/cc_worker.cc | 3 +- srsenb/src/phy/nr/sf_worker.cc | 12 +- srsue/hdr/phy/nr/cc_worker.h | 2 + srsue/hdr/phy/nr/sf_worker.h | 1 + srsue/src/phy/nr/cc_worker.cc | 39 +- srsue/src/phy/nr/sf_worker.cc | 9 + srsue/src/phy/nr/worker_pool.cc | 17 +- srsue/src/stack/rrc/rrc_nr.cc | 9 +- 30 files changed, 1634 insertions(+), 716 deletions(-) create mode 100644 lib/include/srsran/phy/phch/pdcch_cfg_nr.h create mode 100644 lib/src/phy/phch/test/dci_nr_test.c diff --git a/lib/include/srsran/interfaces/rrc_nr_interface_types.h b/lib/include/srsran/interfaces/rrc_nr_interface_types.h index cc0a8efc8..da270dda5 100644 --- a/lib/include/srsran/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srsran/interfaces/rrc_nr_interface_types.h @@ -29,7 +29,7 @@ struct phy_cfg_nr_t { srsran_sch_hl_cfg_nr_t pusch = {}; srsran_pucch_nr_hl_cfg_t pucch = {}; srsran_prach_cfg_t prach = {}; - srsran_ue_dl_nr_pdcch_cfg_t pdcch = {}; + srsran_pdcch_cfg_nr_t pdcch = {}; srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {}; srsran_csi_hl_cfg_t csi = {}; @@ -52,7 +52,7 @@ struct phy_cfg_nr_t { // physicalCellGroupConfig // pdsch-HARQ-ACK-Codebook: dynamic (1) - harq_ack.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; + harq_ack.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; // commonControlResourceSet // controlResourceSetId: 1 @@ -70,39 +70,6 @@ struct phy_cfg_nr_t { } pdcch.coreset_present[1] = true; - // SearchSpace - // searchSpaceId: 1 - // controlResourceSetId: 1 - // monitoringSlotPeriodicityAndOffset: sl1 (0) - // sl1: NULL - // monitoringSymbolsWithinSlot: 8000 [bit length 14, 2 LSB pad bits, 1000 0000 0000 00.. decimal value 8192] - // nrofCandidates - // aggregationLevel1: n0 (0) - // aggregationLevel2: n0 (0) - // aggregationLevel4: n1 (1) - // aggregationLevel8: n0 (0) - // aggregationLevel16: n0 (0) - // searchSpaceType: common (0) - // common - // dci-Format0-0-AndFormat1-0 - srsran_search_space_t search_space1 = {}; - search_space1.id = 1; - search_space1.coreset_id = 1; - search_space1.nof_candidates[0] = 1; - search_space1.nof_candidates[1] = 1; - search_space1.nof_candidates[2] = 1; - search_space1.nof_candidates[3] = 0; - search_space1.nof_candidates[4] = 0; - search_space1.type = srsran_search_space_type_common_3; - pdcch.search_space[1] = search_space1; - pdcch.search_space_present[1] = true; - - // ra-SearchSpace: 1 - pdcch.ra_rnti = 0x16; //< Supposed to be deduced from PRACH configuration - pdcch.ra_search_space = search_space1; - pdcch.ra_search_space.type = srsran_search_space_type_common_1; - pdcch.ra_search_space_present = true; - // spCellConfigDedicated // initialDownlinkBWP // pdcch-Config: setup (1) @@ -126,32 +93,6 @@ struct phy_cfg_nr_t { } pdcch.coreset_present[2] = true; - // searchSpacesToAddModList: 1 item - // Item 0 - // SearchSpace - // searchSpaceId: 2 - // controlResourceSetId: 2 - // monitoringSlotPeriodicityAndOffset: sl1 (0) - // sl1: NULL - // monitoringSymbolsWithinSlot: 8000 [bit length 14, 2 LSB pad bits, 1000 0000 0000 - // 00.. decimal value 8192] nrofCandidates - // aggregationLevel1: n0 (0) - // aggregationLevel2: n2 (2) - // aggregationLevel4: n1 (1) - // aggregationLevel8: n0 (0) - // aggregationLevel16: n0 (0) - // searchSpaceType: ue-Specific (1) - // ue-Specific - // dci-Formats: formats0-0-And-1-0 (0) - pdcch.search_space[2].id = 2; - pdcch.search_space[2].coreset_id = 2; - pdcch.search_space[2].nof_candidates[0] = 0; - pdcch.search_space[2].nof_candidates[1] = 2; - pdcch.search_space[2].nof_candidates[2] = 1; - pdcch.search_space[2].nof_candidates[3] = 0; - pdcch.search_space[2].nof_candidates[4] = 0; - pdcch.search_space[2].type = srsran_search_space_type_ue; - pdcch.search_space_present[2] = true; // pdsch-Config: setup (1) // setup // dmrs-DownlinkForPDSCH-MappingTypeA: setup (1) @@ -956,6 +897,71 @@ struct phy_cfg_nr_t { csi.reports[0].freq_cfg = SRSRAN_CSI_REPORT_FREQ_WIDEBAND; csi.reports[0].cqi_table = SRSRAN_CSI_CQI_TABLE_2; } + + /** + * @param carrier + */ + srsran_dci_cfg_nr_t get_dci_cfg(const srsran_carrier_nr_t& carrier) const + { + srsran_dci_cfg_nr_t dci_cfg = {}; + + // Set bandwidths + dci_cfg.coreset0_bw = pdcch.coreset_present[0] ? srsran_coreset_get_bw(&pdcch.coreset[0]) : 0; + dci_cfg.bwp_dl_initial_bw = carrier.nof_prb; + dci_cfg.bwp_dl_active_bw = carrier.nof_prb; + dci_cfg.bwp_ul_initial_bw = carrier.nof_prb; + dci_cfg.bwp_ul_active_bw = carrier.nof_prb; + + // Iterate over all SS to select monitoring options + for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; i++) { + // Skip not configured SS + if (not pdcch.search_space_present[i]) { + continue; + } + + // Iterate all configured formats + for (uint32_t j = 0; j < pdcch.search_space[i].nof_formats; j++) { + if (pdcch.search_space[i].type == srsran_search_space_type_common_3 && + pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) { + dci_cfg.monitor_common_0_0 = true; + } else if (pdcch.search_space[i].type == srsran_search_space_type_ue && + pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) { + dci_cfg.monitor_0_0_and_1_0 = true; + } else if (pdcch.search_space[i].type == srsran_search_space_type_ue && + pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_1) { + dci_cfg.monitor_0_1_and_1_1 = true; + } + } + } + + // Set PUSCH parameters + dci_cfg.enable_sul = false; + dci_cfg.enable_hopping = false; + + // Set Format 0_1 and 1_1 parameters + dci_cfg.carrier_indicator_size = 0; + dci_cfg.harq_ack_codebok = harq_ack.harq_ack_codebook; + + // Format 0_1 specific configuration (for PUSCH only) + dci_cfg.nof_ul_bwp = 1; + dci_cfg.nof_ul_time_res = (pusch.nof_dedicated_time_ra > 0) + ? pusch.nof_dedicated_time_ra + : (pusch.nof_common_time_ra > 0) ? pusch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA; + dci_cfg.nof_srs = 1; + dci_cfg.nof_ul_layers = 1; + dci_cfg.nof_rb_groups = 1; + dci_cfg.pusch_alloc_type = pusch.alloc; + + // Format 1_1 specific configuration (for PDSCH only) + dci_cfg.nof_dl_bwp = 1; + dci_cfg.pdsch_alloc_type = pdsch.alloc; + dci_cfg.nof_dl_time_res = (pdsch.nof_dedicated_time_ra > 0) + ? pdsch.nof_dedicated_time_ra + : (pdsch.nof_common_time_ra > 0) ? pdsch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA; + dci_cfg.nof_aperiodic_zp = 0; + + return dci_cfg; + }; }; } // namespace srsran diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index a3d8ee7c8..f92667ec6 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -113,7 +113,7 @@ extern "C" { * @brief Maximum number of PDSCH time domain resource allocations. This is defined by TS 38.331 v15.10.0 * as maxNrofDL-Allocations */ -#define SRSRAN_MAX_NOF_DL_ALLOCATION 16 +#define SRSRAN_MAX_NOF_TIME_RA 16 /** * @brief Maximum dl-DataToUL-ACK value. This is defined by TS 38.331 v15.10.1 in PUCCH-Config @@ -143,7 +143,7 @@ typedef enum SRSRAN_API { typedef enum SRSRAN_API { srsran_sch_mapping_type_A = 0, srsran_sch_mapping_type_B } srsran_sch_mapping_type_t; /** - * @brief Search spaces + * @brief Search Space (SS) type * @remark Described in TS 38.213 V15.10.0 Section 10.1 UE procedure for determining physical downlink control channel * assignment */ @@ -209,7 +209,8 @@ typedef enum SRSRAN_API { srsran_dci_format_nr_2_2, ///< @brief Transmission of TPC commands for PUCCH and PUSCH srsran_dci_format_nr_2_3, ///< @brief Transmission of a group of TPC commands for SRS transmissions by one or more UEs srsran_dci_format_nr_rar, ///< @brief Scheduling a transmission of PUSCH from RAR - srsran_dci_format_nr_cg ///< @brief Scheduling of PUSCH using a configured grant + srsran_dci_format_nr_cg, ///< @brief Scheduling of PUSCH using a configured grant + SRSRAN_DCI_FORMAT_NR_COUNT ///< @brief Number of DCI formats } srsran_dci_format_nr_t; /** @@ -232,7 +233,18 @@ typedef enum SRSRAN_API { srsran_pdsch_harq_ack_codebook_none = 0, srsran_pdsch_harq_ack_codebook_semi_static, srsran_pdsch_harq_ack_codebook_dynamic, -} srsran_pdsch_harq_ack_codebook_t; +} srsran_harq_ack_codebook_t; + +/** + * @brief PDSCH/PUSCH Resource allocation configuration + * @remark Described in TS 38.331 V15.10.0 PhysicalCellGroupConfig + */ +typedef enum SRSRAN_API { + srsran_resource_alloc_type0 = 0, + srsran_resource_alloc_type1, + srsran_resource_alloc_dynamic, +} srsran_resource_alloc_t; + /** * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP) */ @@ -303,8 +315,10 @@ typedef struct SRSRAN_API { typedef struct SRSRAN_API { uint32_t id; uint32_t coreset_id; - uint32_t duration; // in slots - srsran_search_space_type_t type; + uint32_t duration; ///< SS duration length in slots + srsran_search_space_type_t type; ///< Sets the SS type, common (multiple types) or UE specific + srsran_dci_format_nr_t formats[SRSRAN_DCI_FORMAT_NR_COUNT]; ///< Specifies the DCI formats that shall be searched + uint32_t nof_formats; uint32_t nof_candidates[SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR]; } srsran_search_space_t; @@ -334,6 +348,13 @@ typedef struct SRSRAN_API { */ SRSRAN_API const char* srsran_rnti_type_str(srsran_rnti_type_t rnti_type); +/** + * @brief Get the RNTI type name for NR + * @param rnti_type RNTI type name + * @return Constant string with the RNTI type name + */ +SRSRAN_API const char* srsran_dci_format_nr_string(srsran_dci_format_nr_t format); + /** * @brief Calculates the bandwidth of a given CORESET in physical resource blocks (PRB) . This function uses the * frequency domain resources bit-map for counting the number of PRB. diff --git a/lib/include/srsran/phy/enb/enb_dl_nr.h b/lib/include/srsran/phy/enb/enb_dl_nr.h index 61d05c45b..4e5601a1e 100644 --- a/lib/include/srsran/phy/enb/enb_dl_nr.h +++ b/lib/include/srsran/phy/enb/enb_dl_nr.h @@ -15,6 +15,7 @@ #include "srsran/phy/common/phy_common_nr.h" #include "srsran/phy/dft/ofdm.h" +#include "srsran/phy/phch/pdcch_cfg_nr.h" #include "srsran/phy/phch/pdcch_nr.h" #include "srsran/phy/phch/pdsch_nr.h" @@ -26,10 +27,10 @@ typedef struct SRSRAN_API { } srsran_enb_dl_nr_args_t; typedef struct SRSRAN_API { - uint32_t max_prb; - uint32_t nof_tx_antennas; - srsran_carrier_nr_t carrier; - srsran_coreset_t coreset; + uint32_t max_prb; + uint32_t nof_tx_antennas; + srsran_carrier_nr_t carrier; + srsran_pdcch_cfg_nr_t pdcch_cfg; srsran_ofdm_t fft[SRSRAN_MAX_PORTS]; @@ -37,6 +38,7 @@ typedef struct SRSRAN_API { srsran_pdsch_nr_t pdsch; srsran_dmrs_sch_t dmrs; + srsran_dci_nr_t dci; ///< Stores DCI configuration srsran_pdcch_nr_t pdcch; } srsran_enb_dl_nr_t; @@ -45,7 +47,9 @@ srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS], con SRSRAN_API int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_t* carrier); -SRSRAN_API int srsran_enb_dl_nr_set_coreset(srsran_enb_dl_nr_t* q, const srsran_coreset_t* coreset); +SRSRAN_API int srsran_enb_dl_nr_set_pdcch_config(srsran_enb_dl_nr_t* q, + const srsran_pdcch_cfg_nr_t* cfg, + const srsran_dci_cfg_nr_t* dci_cfg); SRSRAN_API void srsran_enb_dl_nr_free(srsran_enb_dl_nr_t* q); diff --git a/lib/include/srsran/phy/phch/dci_nr.h b/lib/include/srsran/phy/phch/dci_nr.h index 342d4e68a..32fa35daa 100644 --- a/lib/include/srsran/phy/phch/dci_nr.h +++ b/lib/include/srsran/phy/phch/dci_nr.h @@ -17,24 +17,131 @@ #include "srsran/phy/common/phy_common_nr.h" #include "srsran/phy/phch/phch_cfg_nr.h" +/** + * @brief Maximum number of NR DCI sizes the UE shall search for a given serving cell + */ +#define SRSRAN_DCI_NR_MAX_NOF_SIZES 4 + +/** + * @brief DCI configuration given a serving cell + */ +typedef struct SRSRAN_API { + /// Bandwidth parameters + uint32_t coreset0_bw; ///< CORESET0 DL bandwidth, set to 0 if not present + uint32_t bwp_dl_initial_bw; ///< Initial DL BWP bandwidth + uint32_t bwp_dl_active_bw; ///< Active DL BWP bandwidth in PRB + uint32_t bwp_ul_initial_bw; ///< Initial UL BWP bandwidth + uint32_t bwp_ul_active_bw; ///< Active UL BWP bandwidth in PRB + + /// Search space derived parameters + bool monitor_common_0_0; ///< Set to true if Format 0_0 is monitored in common SS + bool monitor_0_0_and_1_0; ///< Set to true if Format 0_0 is monitored in UE-specific SS + bool monitor_0_1_and_1_1; ///< Set to true if Formats 0_1 and 1_1 are monitored in UE-specific SS + + /// PUSCH configuration derived parameters + bool enable_sul; ///< Set to true if supplementary uplink is configured + bool enable_hopping; ///< Set to true if frequency hopping is enabled + + /// Common Formats 0_1 and 1_1 + uint32_t carrier_indicator_size; ///< Defined in TS 38.213 clause 10.1 + srsran_harq_ack_codebook_t harq_ack_codebok; ///< PDSCH HARQ-ACK codebook mode + uint32_t nof_rb_groups; ///< Defined in TS 38.214 clause 6.1.2.2.1 + + /// Format 0_1 specific configuration (for PUSCH only) + uint32_t nof_ul_bwp; ///< Number of UL BWPs excluding the initial UL BWP, mentioned in the TS as N_BWP_RRC + uint32_t nof_ul_time_res; ///< Number of dedicated PUSCH time domain resource assigment, set to 0 for default + uint32_t nof_srs; ///< Number of configured SRS resources + uint32_t nof_ul_layers; ///< Set to the maximum number of layers for PUSCH + uint32_t pusch_nof_cbg; ///< determined by maxCodeBlockGroupsPerTransportBlock for PUSCH + uint32_t report_trigger_size; ///< determined by reportTriggerSize + bool enable_transform_precoding; ///< Set to true if PUSCH transform precoding is enabled + bool dynamic_dual_harq_ack_codebook; ///< Set to true if HARQ-ACK codebook is set to dynamic with 2 sub-codebooks + bool pusch_tx_config_codebook; ///< Set to true if PUSCH txConfig is set to codebook + bool pusch_dmrs_type2; ///< Set to true if PUSCH DMRS are type 2 + bool pusch_dmrs_double; ///< Set to true if PUSCH DMRS are 2 symbol long + bool pusch_ptrs; ///< Set to true if PT-RS are enabled for PUSCH transmission + bool pusch_dynamic_betas; ///< Set to true if beta offsets operation is not semi-static + srsran_resource_alloc_t pusch_alloc_type; ///< PUSCH resource allocation type + + /// Format 1_1 specific configuration (for PDSCH only) + uint32_t nof_dl_bwp; ///< Number of DL BWPs excluding the initial UL BWP, mentioned in the TS as N_BWP_RRC + srsran_resource_alloc_t pdsch_alloc_type; ///< PDSCH resource allocation type, set to 0 for default + uint32_t nof_dl_time_res; ///< Number of dedicated PDSCH time domain resource assigment + uint32_t nof_aperiodic_zp; ///< Number of aperiodic ZP CSI-RS resource sets configured + bool pdsch_inter_prb_to_prb; ///< Set to true if interleaved VRB to PRB mapping is enabled + bool pdsch_rm_pattern1; ///< Set to true if rateMatchPatternGroup1 is configured + bool pdsch_rm_pattern2; ///< Set to true if rateMatchPatternGroup2 is configured + bool pdsch_2cw; ///< Set to true if maxNrofCodeWordsScheduledByDCI is set to 2 in any BWP + uint32_t pdsch_nof_cbg; ///< determined by maxCodeBlockGroupsPerTransportBlock for PDSCH + bool multiple_scell; ///< Set to true if configured with multiple serving cell + bool nof_dl_to_ul_ack; ///< Number of entries in the dl-DataToUL-ACK + bool pdsch_dmrs_type2; ///< Set to true if PDSCH DMRS are type 2 + bool pdsch_dmrs_double; ///< Set to true if PDSCH DMRS are 2 symbol long + bool pdsch_tci; ///< Set to true if tci-PresentInDCI is enabled + bool pdsch_cbg_flush; ///< Set to true if codeBlockGroupFlushIndicator is true + bool pdsch_dynamic_bundling; ///< Set to true if prb-BundlingType is set to dynamicBundling + +} srsran_dci_cfg_nr_t; + +/** + * @brief NR-DCI object. Stores DCI configuration and pre-calculated DCI sizes + */ +typedef struct SRSRAN_API { + /// Configuration parameters + srsran_dci_cfg_nr_t cfg; + + /// Formats 0_0 and 1_0 in common SS + uint32_t dci_0_0_and_1_0_common_size; ///< DCI format 0_0 and 1_0 in common SS size + uint32_t dci_0_0_common_trunc; ///< DCI format 0_0 in common SS truncation + uint32_t dci_0_0_common_padd; ///< DCI format 0_0 in common SS padding + + /// Formats 0_0 and 1_0 in UE-specific SS + uint32_t dci_0_0_and_1_0_ue_size; ///< DCI format 0_0 and 1_0 in UE-specific SS size + uint32_t dci_0_0_ue_padd; ///< DCI format 0_0 in ue SS padding + uint32_t dci_1_0_ue_padd; ///< DCI format 1_0 in ue SS padding + + /// Formats 0_1 and 1_0 (UE-specific SS only) + uint32_t dci_0_1_size; ///< DCI format 0_1 size + uint32_t dci_0_1_padd; ///< DCI format 0_1 padding + uint32_t dci_1_1_size; ///< DCI format 0_1 size + uint32_t dci_1_1_padd; ///< DCI format 1_1 padding + +} srsran_dci_nr_t; + +/** + * @brief Describes the NR DCI search context + */ +typedef struct SRSRAN_API { + srsran_dci_location_t location; ///< DCI location + srsran_search_space_type_t ss_type; ///< Search space type + uint32_t coreset_id; ///< CORESET identifier + srsran_rnti_type_t rnti_type; ///< RNTI type + srsran_dci_format_nr_t format; ///< DCI format + uint16_t rnti; ///< UE temporal RNTI + uint32_t coreset0_bw; ///< CORESET0 DL bandwidth, set to 0 if not present + uint32_t bwp_dl_initial_bw; ///< Initial DL/UL BWP bandwidth + uint32_t bwp_dl_active_bw; ///< Active DL/UL BWP bandwidth in PRB + uint32_t bwp_ul_initial_bw; ///< Initial UL BWP bandwidth + uint32_t bwp_ul_active_bw; ///< Active UL BWP bandwidth in PRB + bool monitor_common_0_0; ///< Set to true if Format 0_0 is monitored in common SS + bool enable_sul; ///< Set to true if supplementary uplink is configured + bool enable_hopping; ///< Set to true if frequency hopping is enabled +} srsran_dci_ctx_t; + +/** + * @brief Describes any packed format NR DCI message + */ typedef struct SRSRAN_API { - srsran_dci_location_t location; - srsran_search_space_type_t search_space; - uint32_t coreset_id; - uint8_t payload[50]; - srsran_rnti_type_t rnti_type; - uint32_t nof_bits; - srsran_dci_format_nr_t format; - uint16_t rnti; + srsran_dci_ctx_t ctx; ///< DCI context + uint8_t payload[50]; + uint32_t nof_bits; } srsran_dci_msg_nr_t; +/** + * @brief Describes an unpacked DL NR DCI message + */ typedef struct SRSRAN_API { - uint16_t rnti; - srsran_rnti_type_t rnti_type; - srsran_dci_format_nr_t format; - srsran_dci_location_t location; - srsran_search_space_type_t search_space; - uint32_t coreset_id; + srsran_dci_ctx_t ctx; ///< DCI search context // Common fields uint32_t freq_domain_assigment; ///< Frequency domain resource assignment @@ -62,14 +169,13 @@ typedef struct SRSRAN_API { } srsran_dci_dl_nr_t; +/** + * @brief Describes an unpacked UL NR DCI message + * @remark NR RAR UL DCI Described in TS 38.213 Table 8.2-1: Random Access Response Grant Content field size + */ typedef struct SRSRAN_API { // Context information - uint16_t rnti; - srsran_rnti_type_t rnti_type; - srsran_dci_format_nr_t format; - srsran_dci_location_t location; - srsran_search_space_type_t search_space; - uint32_t coreset_id; + srsran_dci_ctx_t ctx; ///< Context information // Common fields uint32_t freq_domain_assigment; ///< Frequency domain resource assignment @@ -91,60 +197,93 @@ typedef struct SRSRAN_API { // Random Access Response Grant uint32_t csi_request; + + // Other fields + uint32_t sul; ///< Supplementary Uplink flag } srsran_dci_ul_nr_t; /** - * @brief Indicates whether the provided DCI message format bit indicator belongs to DCI format 1_0 according according - * to the RNTI type. If invalid, the DCI message is likely to be format 0_0 - * @param dci_msg Provides DCI format 1_0 message - * @return true if the DCI message is format 1_0, false otherwise + * @brief Set NR-DCI configuration for a given cell. This function will pre-compute the DCI sizes, padding, truncation + * and so on from a given DCI configuration. + * @remark Implemented according TS 38.212 section 7.3.1.0 DCI size alignment + * @param[in,out] dci DCI object + * @param[in] cfg NR-DCI configuration + * @return SRSLTE_SUCCESS if the configuration is valid, SRSLTE_ERROR code otherwise */ -SRSRAN_API bool srsran_dci_nr_format_1_0_valid(const srsran_dci_msg_nr_t* dci_msg); +SRSRAN_API int srsran_dci_nr_set_cfg(srsran_dci_nr_t* dci, const srsran_dci_cfg_nr_t* cfg); -SRSRAN_API int srsran_dci_nr_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - const srsran_dci_dl_nr_t* dci, - srsran_dci_msg_nr_t* msg); - -SRSRAN_API int srsran_dci_nr_format_0_0_sizeof(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_rnti_type_t rnti_type); +/** + * @brief Calculates a DL NR-DCI size for a given SS type and format + * @attention Only DCI 0_0 and 1_0 can be in common search-space + * @param q NR DCI object + * @param ss_type Search Space type + * @param format NR DCI format + * @return The number of bis for the DCI message if configured, 0 otherwise + */ +SRSRAN_API uint32_t srsran_dci_nr_size(const srsran_dci_nr_t* q, + srsran_search_space_type_t ss_type, + srsran_dci_format_nr_t format); -SRSRAN_API int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset0, - const srsran_dci_ul_nr_t* dci, - srsran_dci_msg_nr_t* msg); +/** + * @brief Indicates whether the provided DCI message format bit indicator belongs to the a Dl DCI format (1_0 or 1_1) + * according according to the RNTI type. If invalid, the DCI message is likely to be an UL DCI + * @param dci Provides DCI format message + * @return true if the DCI message is for DL, false otherwise + */ +SRSRAN_API bool srsran_dci_nr_valid_direction(const srsran_dci_msg_nr_t* dci); -SRSRAN_API int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_dci_msg_nr_t* msg, - srsran_dci_ul_nr_t* dci); +/** + * @brief Packs a DL NR DCI into a DCI message + * @param q NR DCI object with precomputed DCI parameters + * @param dci DL NR DCI to pack (serialize) + * @param[out] msg Resultant packed DCI message + * @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg); /** - * @brief Unpacks DCI from Random Access Response Grant - * @remark Described in TS 38.213 Table 8.2-1: Random Access Response Grant Content field size - * @param msg - * @param dci - * @return SRSRAN_SUCCESS if unpacked correctly, SRSRAN_ERROR code otherwise + * @brief Unpacks an NR DCI message into a DL NR DCI + * @param q NR DCI object with precomputed DCI parameters + * @param msg DCI message to unpack (deserialize) + * @param[out] dci Resultant unpacked DL DCI + * @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise */ -SRSRAN_API int srsran_dci_nr_rar_unpack(srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci); +SRSRAN_API int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci); -SRSRAN_API int srsran_dci_nr_format_1_0_sizeof(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_rnti_type_t rnti_type); +/** + * @brief Packs an UL NR DCI into a DCI message + * @param q NR DCI object with precomputed DCI parameters + * @param dci UL NR DCI to pack (serialize) + * @param[out] msg resultant DCI message + * @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg); -SRSRAN_API int srsran_dci_nr_format_1_0_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - const srsran_dci_dl_nr_t* dci, - srsran_dci_msg_nr_t* msg); +/** + * @brief Unpacks an NR DCI message into an UL NR DCI + * @param q NR DCI object with precomputed DCI parameters + * @param msg DCI message to unpack (deserialize) + * @param[out] dci Resultant unpacked UL DCI + * @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci); -SRSRAN_API int srsran_dci_nr_format_1_0_unpack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_dci_msg_nr_t* msg, - srsran_dci_dl_nr_t* dci); +/** + * @brief Stringifies an DL NR DCI structure + * @param dci DL NR SCI structure to stringify + * @param[out] str Destination string + * @param str_len Destination string length + * @return The number of written characters + */ +SRSRAN_API int srsran_dci_dl_nr_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len); +/** + * @brief Stringifies an UL NR DCI structure + * @param dci UL NR SCI structure to stringify + * @param[out] str Destination string + * @param str_len Destination string length + * @return The number of written characters + */ SRSRAN_API int srsran_dci_ul_nr_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len); -SRSRAN_API int srsran_dci_dl_nr_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len); - #endif // SRSRAN_DCI_NR_H diff --git a/lib/include/srsran/phy/phch/pdcch_cfg_nr.h b/lib/include/srsran/phy/phch/pdcch_cfg_nr.h new file mode 100644 index 000000000..edffb2d3f --- /dev/null +++ b/lib/include/srsran/phy/phch/pdcch_cfg_nr.h @@ -0,0 +1,44 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_PDCCH_CFG_NR_H +#define SRSRAN_PDCCH_CFG_NR_H + +#include "dci_nr.h" + +/** + * Maximum number of CORESET + * @remark Defined in TS 38.331 by maxNrofControlResourceSets-1 + */ +#define SRSRAN_UE_DL_NR_MAX_NOF_CORESET 12 + +/** + * Maximum number of Search spaces + * @remark Defined in TS 38.331 by maxNrofSearchSpaces-1 + */ +#define SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE 40 + +/** + * @brief PDCCH configuration provided by upper layers + */ +typedef struct SRSRAN_API { + srsran_coreset_t coreset[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< PDCCH Control resource sets (CORESET) collection + bool coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< CORESET present flags + + srsran_search_space_t search_space[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE]; + bool search_space_present[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE]; + + srsran_search_space_t ra_search_space; + bool ra_search_space_present; +} srsran_pdcch_cfg_nr_t; + +#endif // SRSRAN_PDCCH_CFG_NR_H diff --git a/lib/include/srsran/phy/phch/phch_cfg_nr.h b/lib/include/srsran/phy/phch/phch_cfg_nr.h index 95b49d934..6f20e4d6e 100644 --- a/lib/include/srsran/phy/phch/phch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/phch_cfg_nr.h @@ -201,13 +201,14 @@ typedef struct SRSRAN_API { bool present; } dmrs_typeB; - srsran_sch_time_ra_t common_time_ra[SRSRAN_MAX_NOF_DL_ALLOCATION]; + srsran_sch_time_ra_t common_time_ra[SRSRAN_MAX_NOF_TIME_RA]; uint32_t nof_common_time_ra; - srsran_sch_time_ra_t dedicated_time_ra[SRSRAN_MAX_NOF_DL_ALLOCATION]; + srsran_sch_time_ra_t dedicated_time_ra[SRSRAN_MAX_NOF_TIME_RA]; uint32_t nof_dedicated_time_ra; - bool rbg_size_cfg_1; ///< RBG size configuration (1 or 2) + bool rbg_size_cfg_1; ///< RBG size configuration (1 or 2) + srsran_resource_alloc_t alloc; srsran_sch_cfg_t sch_cfg; ///< Common shared channel parameters diff --git a/lib/include/srsran/phy/ue/ue_dl_nr.h b/lib/include/srsran/phy/ue/ue_dl_nr.h index c95744430..26bf5437e 100644 --- a/lib/include/srsran/phy/ue/ue_dl_nr.h +++ b/lib/include/srsran/phy/ue/ue_dl_nr.h @@ -17,22 +17,11 @@ #include "srsran/phy/common/phy_common_nr.h" #include "srsran/phy/dft/ofdm.h" #include "srsran/phy/phch/dci_nr.h" +#include "srsran/phy/phch/pdcch_cfg_nr.h" #include "srsran/phy/phch/pdcch_nr.h" #include "srsran/phy/phch/pdsch_nr.h" #include "srsran/phy/phch/uci_cfg_nr.h" -/** - * Maximum number of CORESET - * @remark Defined in TS 38.331 by maxNrofControlResourceSets-1 - */ -#define SRSRAN_UE_DL_NR_MAX_NOF_CORESET 12 - -/** - * Maximum number of Search spaces - * @remark Defined in TS 38.331 by maxNrofSearchSpaces-1 - */ -#define SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE 40 - /** * Maximum number of DCI messages to receive */ @@ -47,18 +36,6 @@ typedef struct SRSRAN_API { float pdcch_dmrs_epre_thr; } srsran_ue_dl_nr_args_t; -typedef struct SRSRAN_API { - srsran_coreset_t coreset[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< PDCCH Control resource sets (CORESET) collection - bool coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< CORESET present flags - - srsran_search_space_t search_space[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE]; - bool search_space_present[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE]; - - uint16_t ra_rnti; ///< Needs to be deduced from the PRACH configuration - srsran_search_space_t ra_search_space; - bool ra_search_space_present; -} srsran_ue_dl_nr_pdcch_cfg_t; - typedef struct { uint32_t scell_idx; ///< Serving cell index uint32_t v_dai_dl; ///< Downlink Assigment Index @@ -93,9 +70,9 @@ typedef struct { } srsran_pdsch_ack_nr_t; typedef struct SRSRAN_API { - bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided - bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided - srsran_pdsch_harq_ack_codebook_t pdsch_harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration + bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided + bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided + srsran_harq_ack_codebook_t harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration bool max_cw_sched_dci_is_2; ///< Param maxNrofCodeWordsScheduledByDCI, set to true if present and equal to 2 uint32_t dl_data_to_ul_ack[SRSRAN_MAX_NOF_DL_DATA_TO_UL]; @@ -103,11 +80,10 @@ typedef struct SRSRAN_API { } srsran_ue_dl_nr_harq_ack_cfg_t; typedef struct SRSRAN_API { - uint32_t coreset_id; - uint32_t ss_id; - srsran_dci_location_t location; + srsran_dci_ctx_t dci_ctx; srsran_dmrs_pdcch_measure_t measure; srsran_pdcch_nr_res_t result; + uint32_t nof_bits; } srsran_ue_dl_nr_pdcch_info_t; typedef struct SRSRAN_API { @@ -116,8 +92,8 @@ typedef struct SRSRAN_API { float pdcch_dmrs_corr_thr; float pdcch_dmrs_epre_thr; - srsran_carrier_nr_t carrier; - srsran_ue_dl_nr_pdcch_cfg_t cfg; + srsran_carrier_nr_t carrier; + srsran_pdcch_cfg_nr_t cfg; srsran_ofdm_t fft[SRSRAN_MAX_PORTS]; @@ -134,12 +110,15 @@ typedef struct SRSRAN_API { srsran_ue_dl_nr_pdcch_info_t pdcch_info[SRSRAN_MAX_NOF_CANDIDATES_SLOT_NR]; uint32_t pdcch_info_count; + /// DCI packing/unpacking object + srsran_dci_nr_t dci; + /// Temporally stores Found DCI messages from all SS - srsran_dci_msg_nr_t dci_msg[SRSRAN_MAX_DCI_MSG_NR]; - uint32_t dci_msg_count; + srsran_dci_msg_nr_t dl_dci_msg[SRSRAN_MAX_DCI_MSG_NR]; + uint32_t dl_dci_msg_count; - srsran_dci_msg_nr_t pending_ul_dci_msg[SRSRAN_MAX_DCI_MSG_NR]; - uint32_t pending_ul_dci_count; + srsran_dci_msg_nr_t ul_dci_msg[SRSRAN_MAX_DCI_MSG_NR]; + uint32_t ul_dci_count; } srsran_ue_dl_nr_t; SRSRAN_API int @@ -147,7 +126,9 @@ srsran_ue_dl_nr_init(srsran_ue_dl_nr_t* q, cf_t* input[SRSRAN_MAX_PORTS], const SRSRAN_API int srsran_ue_dl_nr_set_carrier(srsran_ue_dl_nr_t* q, const srsran_carrier_nr_t* carrier); -SRSRAN_API int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr_pdcch_cfg_t* cfg); +SRSRAN_API int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, + const srsran_pdcch_cfg_nr_t* cfg, + const srsran_dci_cfg_nr_t* dci_cfg); SRSRAN_API void srsran_ue_dl_nr_free(srsran_ue_dl_nr_t* q); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index ee78d9596..72e644154 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -268,13 +268,13 @@ bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg, srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg; switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) { case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value: - srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; + srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; break; case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::semi_static: - srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_semi_static; + srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_semi_static; break; case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::nulltype: - srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_none; + srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_none; break; default: asn1::log_warning("Invalid option for pdsch_harq_ack_codebook %s", @@ -312,9 +312,51 @@ bool make_phy_search_space_cfg(const search_space_s& search_space, srsran_search switch (search_space.search_space_type.type()) { case search_space_s::search_space_type_c_::types_opts::options::common: srsran_search_space.type = srsran_search_space_type_common_3; + + // dci-Format0-0-AndFormat1-0 + // If configured, the UE monitors the DCI formats 0_0 and 1_0 according to TS 38.213 [13], clause 10.1. + if (search_space.search_space_type.common().dci_format0_minus0_and_format1_minus0_present) { + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_0; + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_0; + } + + // dci-Format2-0 + // If configured, UE monitors the DCI format 2_0 according to TS 38.213 [13], clause 10.1, 11.1.1. + if (search_space.search_space_type.common().dci_format2_minus0_present) { + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_0; + } + + // dci-Format2-1 + // If configured, UE monitors the DCI format 2_1 according to TS 38.213 [13], clause 10.1, 11.2. + if (search_space.search_space_type.common().dci_format2_minus1_present) { + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_1; + } + + // dci-Format2-2 + // If configured, UE monitors the DCI format 2_2 according to TS 38.213 [13], clause 10.1, 11.3. + if (search_space.search_space_type.common().dci_format2_minus2_present) { + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_2; + } + + // dci-Format2-3 + // If configured, UE monitors the DCI format 2_3 according to TS 38.213 [13], clause 10.1, 11.4 + if (search_space.search_space_type.common().dci_format2_minus3_present) { + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_3; + } + break; case search_space_s::search_space_type_c_::types_opts::options::ue_specific: srsran_search_space.type = srsran_search_space_type_ue; + switch (search_space.search_space_type.ue_specific().dci_formats.value) { + case search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_e_::formats0_minus0_and_minus1_minus0: + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_0; + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_0; + break; + case search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_e_::formats0_minus1_and_minus1_minus1: + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_1; + srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_1; + break; + } break; default: asn1::log_warning("Invalid option for search_space_type %s", search_space.search_space_type.type().to_string()); diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 6f9e49337..ad4635d2d 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -37,6 +37,36 @@ const char* srsran_rnti_type_str(srsran_rnti_type_t rnti_type) return "unknown"; } +const char* srsran_dci_format_nr_string(srsran_dci_format_nr_t format) +{ + switch (format) { + case srsran_dci_format_nr_0_0: + return "0_0"; + case srsran_dci_format_nr_0_1: + return "0_1"; + case srsran_dci_format_nr_1_0: + return "1_0"; + case srsran_dci_format_nr_1_1: + return "1_1"; + case srsran_dci_format_nr_2_0: + return "2_0"; + case srsran_dci_format_nr_2_1: + return "2_1"; + case srsran_dci_format_nr_2_2: + return "2_2"; + case srsran_dci_format_nr_2_3: + return "2_3"; + case srsran_dci_format_nr_rar: + return "RAR"; + case srsran_dci_format_nr_cg: + return "CG"; + default: + case SRSRAN_DCI_FORMAT_NR_COUNT: + break; + } + return "unknown"; +} + uint32_t srsran_coreset_get_bw(const srsran_coreset_t* coreset) { uint32_t prb_count = 0; diff --git a/lib/src/phy/enb/enb_dl_nr.c b/lib/src/phy/enb/enb_dl_nr.c index 09188dd39..b78928e02 100644 --- a/lib/src/phy/enb/enb_dl_nr.c +++ b/lib/src/phy/enb/enb_dl_nr.c @@ -135,15 +135,21 @@ int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_ return SRSRAN_SUCCESS; } -int srsran_enb_dl_nr_set_coreset(srsran_enb_dl_nr_t* q, const srsran_coreset_t* coreset) +int srsran_enb_dl_nr_set_pdcch_config(srsran_enb_dl_nr_t* q, + const srsran_pdcch_cfg_nr_t* cfg, + const srsran_dci_cfg_nr_t* dci_cfg) { - if (q == NULL || coreset == NULL) { + if (q == NULL || cfg == NULL) { return SRSRAN_ERROR_INVALID_INPUTS; } - q->coreset = *coreset; + q->pdcch_cfg = *cfg; - if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, &q->coreset) < SRSRAN_SUCCESS) { + if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, &q->pdcch_cfg.coreset[0]) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_dci_nr_set_cfg(&q->dci, dci_cfg) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } @@ -182,15 +188,27 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q, return SRSRAN_ERROR_INVALID_INPUTS; } + if (dci_dl->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET || + !q->pdcch_cfg.coreset_present[dci_dl->ctx.coreset_id]) { + ERROR("Invalid CORESET ID %d", dci_dl->ctx.coreset_id); + return SRSRAN_ERROR; + } + srsran_coreset_t* coreset = &q->pdcch_cfg.coreset[dci_dl->ctx.coreset_id]; + + if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, coreset) < SRSRAN_SUCCESS) { + ERROR("Error setting PDCCH carrier/CORESET"); + return SRSRAN_ERROR; + } + // Put DMRS - if (srsran_dmrs_pdcch_put(&q->carrier, &q->coreset, slot_cfg, &dci_dl->location, q->sf_symbols[0]) < SRSRAN_SUCCESS) { + if (srsran_dmrs_pdcch_put(&q->carrier, coreset, slot_cfg, &dci_dl->ctx.location, q->sf_symbols[0]) < SRSRAN_SUCCESS) { ERROR("Error putting PDCCH DMRS"); return SRSRAN_ERROR; } // Pack DCI srsran_dci_msg_nr_t dci_msg = {}; - if (srsran_dci_nr_pack(&q->carrier, &q->coreset, dci_dl, &dci_msg) < SRSRAN_SUCCESS) { + if (srsran_dci_nr_dl_pack(&q->dci, dci_dl, &dci_msg) < SRSRAN_SUCCESS) { ERROR("Error packing DL DCI"); return SRSRAN_ERROR; } @@ -201,7 +219,7 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q, return SRSRAN_ERROR; } - INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->location.L, dci_dl->location.ncce); + INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce); return SRSRAN_SUCCESS; } diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c index 6ba0e51ed..b469e68ff 100644 --- a/lib/src/phy/phch/dci_nr.c +++ b/lib/src/phy/phch/dci_nr.c @@ -13,102 +13,121 @@ #include "srsran/phy/phch/dci_nr.h" #include "srsran/phy/utils/bit.h" #include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" -static int dci_nr_format_0_0_freq_resource_size(const srsran_carrier_nr_t* carrier) +/** + * Defines minimum size according to TS 38.212 section 7.3.1 DCI Formats: + * If the number of information bits in a DCI format is less than 12 bits, zeros shall be appended to the DCI format + * until the payload size equals 12. + */ +#define DCI_NR_MIN_SIZE 12 + +#define CEIL_LOG2(N) (((N) == 0) ? 0 : ceil(log2((double)(N)))) + +static uint32_t dci_nr_freq_resource_size_type1(uint32_t N) { - if (carrier == NULL) { - return SRSRAN_ERROR; + if (N == 0) { + return 0; } - return (int)ceil(log2(carrier->nof_prb * (carrier->nof_prb + 1) / 2.0)); + return (int)CEIL_LOG2(N * (N + 1) / 2.0); } -static int dci_nr_format_1_0_freq_resource_size(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset0, - srsran_rnti_type_t rnti_type) +static uint32_t dci_nr_freq_resource_size(srsran_resource_alloc_t alloc_type, uint32_t N_RBG, uint32_t N_BWP_RB) { - if (carrier == NULL) { - return SRSRAN_ERROR; + // Frequency domain resource assignment + switch (alloc_type) { + case srsran_resource_alloc_type0: + return N_RBG; + case srsran_resource_alloc_type1: + return dci_nr_freq_resource_size_type1(N_BWP_RB); + case srsran_resource_alloc_dynamic: + return SRSRAN_MAX(N_RBG, dci_nr_freq_resource_size_type1(N_BWP_RB)) + 1; + default: + ERROR("Unhandled case"); } - uint32_t N_DL_BWP_RB = carrier->nof_prb; - if (rnti_type == srsran_rnti_type_ra && coreset0 != NULL) { - N_DL_BWP_RB = srsran_coreset_get_bw(coreset0); - } else if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_si) { - if (coreset0 == NULL) { - return SRSRAN_ERROR; - } - N_DL_BWP_RB = srsran_coreset_get_bw(coreset0); + return 0; +} + +static uint32_t dci_nr_bwp_id_size(uint32_t N_BWP_RRC) +{ + uint32_t N_BWP = N_BWP_RRC; + if (N_BWP_RRC <= 3) { + N_BWP = N_BWP_RRC + 1; } - return (int)ceil(log2(N_DL_BWP_RB * (N_DL_BWP_RB + 1) / 2.0)); + return (int)CEIL_LOG2(N_BWP); } -bool srsran_dci_nr_format_1_0_valid(const srsran_dci_msg_nr_t* dci) +static uint32_t dci_nr_time_res_size(uint32_t nof_time_res) { - // Check pointer - if (dci == NULL) { - return false; + if (nof_time_res == 0) { + // 4 bits are necessary for PUSCH default time resource assigment (TS 38.214 Table 6.1.2.1.1-2) + return 4; } + return (uint32_t)CEIL_LOG2(nof_time_res); +} - // Wrong format - if (dci->format != srsran_dci_format_nr_1_0) { - return false; - } +// Determines DCI format 0_0 according to TS 38.212 clause 7.3.1.1.1 +static uint32_t dci_nr_format_0_0_sizeof(uint32_t N_UL_BWP_RB, const srsran_dci_cfg_nr_t* cfg) +{ + uint32_t count = 0; - // The format bit is only present for these RNTI - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { - return dci->payload[0] == 1; + // Identifier for DCI formats – 1 bits + count++; + + // For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset + uint32_t N_UL_hop = (cfg->enable_hopping) ? ((N_UL_BWP_RB < 50) ? 1 : 2) : 0; + count += N_UL_hop; + + // Frequency domain resource assignment + uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB); + if (N < N_UL_hop) { + return 0; } + count += N - N_UL_hop; - // Otherwise, the message might be format 1_0 - return true; -} + // Time domain resource assignment – 4 bits + count += 4; -int srsran_dci_nr_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - const srsran_dci_dl_nr_t* dci, - srsran_dci_msg_nr_t* msg) -{ - // Copy DCI MSG fields - msg->location = dci->location; - msg->search_space = dci->search_space; - msg->coreset_id = dci->coreset_id; - msg->rnti_type = dci->rnti_type; - msg->rnti = dci->rnti; - msg->format = dci->format; + // Frequency hopping flag – 1 bit + count += 1; - // Pack DCI - switch (msg->format) { - case srsran_dci_format_nr_1_0: - if (srsran_dci_nr_format_1_0_pack(carrier, coreset, dci, msg) < SRSRAN_SUCCESS) { - ERROR("Error packing DL DCI"); - return SRSRAN_ERROR; - } - break; - default: - ERROR("Unsupported DCI format %d", msg->format); - return SRSRAN_ERROR; + // Modulation and coding scheme – 5 bits + count += 5; + + // New data indicator – 1 bit + count += 1; + + // Redundancy version – 2 bits + count += 2; + + // HARQ process number – 4 bits + count += 4; + + // TPC command for scheduled PUSCH – 2 bits + count += 2; + + // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0 + if (cfg->enable_sul) { + count++; } - return SRSRAN_SUCCESS; + return count; } -int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset0, - const srsran_dci_ul_nr_t* dci, - srsran_dci_msg_nr_t* msg) +static int dci_nr_format_0_0_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg) { - uint32_t trim = 0; // hard-coded bit trimming - bool enable_hopping = false; // hard-coded PUSCH hopping - uint32_t padding = 8; // Hard-coded padding - bool supplementary_uplink = false; // Hard-coded supplementary Uplink - uint8_t* y = msg->payload; - srsran_rnti_type_t rnti_type = msg->rnti_type; - - if (carrier == NULL) { - return SRSRAN_ERROR; - } + bool is_common_ss = SRSRAN_SEARCH_SPACE_IS_COMMON(msg->ctx.ss_type); + uint32_t trunc = is_common_ss ? q->dci_0_0_common_trunc : 0; // hard-coded bit truncation + uint32_t padding = is_common_ss ? q->dci_0_0_common_padd : q->dci_0_0_ue_padd; // Hard-coded padding + uint8_t* y = msg->payload; + srsran_rnti_type_t rnti_type = msg->ctx.rnti_type; + uint32_t N_UL_BWP_RB = is_common_ss ? q->cfg.bwp_ul_initial_bw : q->cfg.bwp_ul_active_bw; + + // 1st of all, copy DCI context + msg->ctx = dci->ctx; // Check RNTI type if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) { @@ -120,15 +139,15 @@ int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier, y++; // For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset - int N_UL_hop = (enable_hopping) ? ((carrier->nof_prb < 50) ? 1 : 2) : 0; + int N_UL_hop = (q->cfg.enable_hopping) ? (N_UL_BWP_RB ? 1 : 2) : 0; srsran_bit_unpack(dci->frequency_offset, &y, N_UL_hop); // Frequency domain resource assignment - int N = dci_nr_format_0_0_freq_resource_size(carrier); - if (N < SRSRAN_SUCCESS || N - N_UL_hop <= 0) { + uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB); + if (N <= N_UL_hop) { return SRSRAN_ERROR; } - srsran_bit_unpack(dci->freq_domain_assigment, &y, N - N_UL_hop - trim); + srsran_bit_unpack(dci->freq_domain_assigment, &y, (int)(N - N_UL_hop - trunc)); // Time domain resource assignment – 4 bits srsran_bit_unpack(dci->time_domain_assigment, &y, 4); @@ -157,11 +176,11 @@ int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier, } // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0 - if (supplementary_uplink) { + if (q->cfg.enable_sul) { *(y++) = 0; } - msg->nof_bits = srsran_dci_nr_format_0_0_sizeof(carrier, coreset0, rnti_type); + msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_0_0); if (msg->nof_bits != y - msg->payload) { ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload)); return SRSRAN_ERROR; @@ -170,29 +189,15 @@ int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier, return SRSRAN_SUCCESS; } -int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_dci_msg_nr_t* msg, - srsran_dci_ul_nr_t* dci) +static int dci_nr_format_0_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci) { - uint32_t trim = 0; // hard-coded bit trimming - bool enable_hopping = false; // hard-coded PUSCH hopping - uint32_t padding = 8; // Hard-coded padding - bool supplementary_uplink = false; // Hard-coded supplementary Uplink - uint8_t* y = msg->payload; - srsran_rnti_type_t rnti_type = msg->rnti_type; - - // Copy DCI MSG fields - dci->location = msg->location; - dci->search_space = msg->search_space; - dci->coreset_id = msg->coreset_id; - dci->rnti_type = msg->rnti_type; - dci->rnti = msg->rnti; - dci->format = msg->format; - - if (carrier == NULL) { - return SRSRAN_ERROR; - } + uint32_t trim = 0; // hard-coded bit trimming + bool enable_hopping = false; // hard-coded PUSCH hopping + uint32_t padding = 8; // Hard-coded padding + uint8_t* y = msg->payload; + srsran_rnti_type_t rnti_type = msg->ctx.rnti_type; + srsran_search_space_type_t ss_type = msg->ctx.ss_type; + uint32_t N_UL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type) ? q->cfg.bwp_ul_initial_bw : q->cfg.bwp_ul_active_bw; // Check RNTI type if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) { @@ -200,10 +205,9 @@ int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier, return SRSRAN_ERROR; } - if (msg->nof_bits != srsran_dci_nr_format_0_0_sizeof(carrier, coreset, rnti_type)) { - ERROR("Invalid number of bits %d, expected %d", - msg->nof_bits, - srsran_dci_nr_format_0_0_sizeof(carrier, coreset, rnti_type)); + uint32_t nof_bits = srsran_dci_nr_size(q, ss_type, srsran_dci_format_nr_0_0); + if (msg->nof_bits != nof_bits) { + ERROR("Invalid number of bits %d, expected %d", msg->nof_bits, nof_bits); return SRSRAN_ERROR; } @@ -214,12 +218,12 @@ int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier, } // For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset - int N_UL_hop = (enable_hopping) ? ((carrier->nof_prb < 50) ? 1 : 2) : 0; + uint32_t N_UL_hop = (enable_hopping) ? ((N_UL_BWP_RB < 50) ? 1 : 2) : 0; dci->frequency_offset = srsran_bit_pack(&y, N_UL_hop); // Frequency domain resource assignment - int N = dci_nr_format_0_0_freq_resource_size(carrier); - if (N < SRSRAN_SUCCESS || N - N_UL_hop <= 0) { + uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB); + if (N < N_UL_hop) { return SRSRAN_ERROR; } dci->freq_domain_assigment = srsran_bit_pack(&y, N - N_UL_hop - trim); @@ -251,76 +255,20 @@ int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier, } // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0 - if (supplementary_uplink) { - y++; + if (q->cfg.enable_sul) { + dci->sul = srsran_bit_pack(&y, 1); } return SRSRAN_SUCCESS; } -int srsran_dci_nr_format_0_0_sizeof(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_rnti_type_t rnti_type) -{ - uint32_t trim = 0; // hard-coded bit trimming - bool enable_hopping = false; // hard-coded PUSCH hopping - uint32_t padding = 8; // Hard-coded padding - bool supplementary_uplink = false; // Hard-coded supplementary Uplink - int count = 0; - - // Identifier for DCI formats – 1 bits - count++; - - // For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset - int N_UL_hop = (enable_hopping) ? ((carrier->nof_prb < 50) ? 1 : 2) : 0; - count += N_UL_hop; - - // Frequency domain resource assignment - int N = dci_nr_format_0_0_freq_resource_size(carrier); - if (N < SRSRAN_SUCCESS || N - N_UL_hop <= 0) { - return SRSRAN_ERROR; - } - count += N - N_UL_hop - trim; - - // Time domain resource assignment – 4 bits - count += 4; - - // Frequency hopping flag – 1 bit - count += 1; - - // Modulation and coding scheme – 5 bits - count += 5; - - // New data indicator – 1 bit - count += 1; - - // Redundancy version – 2 bits - count += 2; - - // HARQ process number – 4 bits - count += 4; - - // TPC command for scheduled PUSCH – 2 bits - count += 2; - - // Padding goes here - count += padding; - - // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0 - if (supplementary_uplink) { - count++; - } - - return count; -} - static int dci_nr_format_0_0_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len) { uint32_t len = 0; // Print format len = srsran_print_check( - str, str_len, len, "rnti=%04x L=%d cce=%d dci=0_0 ", dci->rnti, dci->location.L, dci->location.ncce); + str, str_len, len, "rnti=%04x L=%d cce=%d dci=0_0 ", dci->ctx.rnti, dci->ctx.location.L, dci->ctx.location.ncce); // Frequency domain resource assignment len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment); @@ -349,404 +297,466 @@ static int dci_nr_format_0_0_to_str(const srsran_dci_ul_nr_t* dci, char* str, ui return len; } -int srsran_dci_nr_rar_unpack(srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci) +static uint32_t dci_nr_format_0_1_sizeof(const srsran_dci_cfg_nr_t* cfg, srsran_rnti_type_t rnti_type) { - if (msg == NULL || dci == NULL) { + uint32_t count = 0; + + if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_sp_csi && + rnti_type != srsran_rnti_type_mcs_c) { + ERROR("Invalid RNTI (%s) for format 0_1", srsran_rnti_type_str(rnti_type)); return SRSRAN_ERROR; } - uint8_t* y = msg->payload; + // Identifier for DCI formats – 1 bit + count += 1; - // Copy DCI MSG fields - dci->location = msg->location; - dci->search_space = msg->search_space; - dci->coreset_id = msg->coreset_id; - dci->rnti_type = msg->rnti_type; - dci->rnti = msg->rnti; - dci->format = msg->format; + // Carrier indicator – 0 or 3 bits + count += SRSRAN_MIN(cfg->carrier_indicator_size, 3); - // Frequency hopping flag - 1 bit - dci->freq_hopping_flag = srsran_bit_pack(&y, 1); + // UL/SUL indicator – 0 bit for UEs not configured with supplementaryUplink ... otherwise, 1 bit + count += cfg->enable_sul ? 1 : 0; - // PUSCH frequency resource allocation - 14 bits - dci->freq_domain_assigment = srsran_bit_pack(&y, 14); + // Bandwidth part indicator – 0, 1 or 2 bits + count += SRSRAN_MIN(dci_nr_bwp_id_size(cfg->nof_ul_bwp), 2); - // PUSCH time resource allocation - 4 bits - dci->time_domain_assigment = srsran_bit_pack(&y, 4); + // Frequency domain resource assignment + count += dci_nr_freq_resource_size(cfg->pusch_alloc_type, cfg->nof_rb_groups, cfg->bwp_ul_active_bw); - // MCS -4 bits - dci->mcs = srsran_bit_pack(&y, 4); + // Time domain resource assigment - 0, 1, 2, 3, or 4 bits + count += dci_nr_time_res_size(cfg->nof_ul_time_res); - // TPC command for PUSCH - 3 bits - dci->tpc = srsran_bit_pack(&y, 3); + // Frequency hopping flag - 0 or 1 bit: + if (cfg->pusch_alloc_type == srsran_resource_alloc_type0 || !cfg->enable_hopping) { + count += 0; + } else { + count += 1; + } - // CSI request - 1 bits - dci->csi_request = srsran_bit_pack(&y, 3); + // Modulation and coding scheme – 5 bits + count += 5; - return SRSRAN_SUCCESS; -} + // New data indicator – 1 bit + count += 1; -static int dci_nr_rar_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len) -{ - uint32_t len = 0; + // Redundancy version – 2 bits + count += 2; - // Print format - len = srsran_print_check(str, str_len, len, "rnti=%04x dci=rar ", dci->rnti); + // HARQ process number – 4 bits + count += 4; - // Frequency hopping flag - len = srsran_print_check(str, str_len, len, "hop=%d ", dci->freq_hopping_flag); + // 1st DAI - 1 or 2 bits + if (cfg->pusch_tx_config_codebook == srsran_pdsch_harq_ack_codebook_semi_static) { + count += 1; + } else { + count += 2; + } - // PUSCH frequency resource allocation - len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment); + // 2st DAI - 0 or 2 bits + if (cfg->dynamic_dual_harq_ack_codebook) { + count += 2; + } else { + count += 0; + } - // PUSCH time resource allocation - len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment); + // TPC command for scheduled PUSCH – 2 bits + count += 2; - // Modulation and coding scheme - len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs); + // SRS resource indicator + uint32_t N_srs = SRSRAN_MIN(1, cfg->nof_srs); + if (cfg->pusch_tx_config_codebook) { + uint32_t N = 0; + for (uint32_t k = 1; k < SRSRAN_MIN(cfg->nof_ul_layers, cfg->nof_srs); k++) { + N += cfg->nof_srs / k; + } + count += (uint32_t)CEIL_LOG2(N); + } else { + count += (uint32_t)CEIL_LOG2(N_srs); + } - // TPC command for scheduled PUSCH - len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc); + // Precoding information and number of layers + if (cfg->pusch_tx_config_codebook) { + ERROR("Not implemented"); + return 0; + } + count += 0; - // CSI request - len = srsran_print_check(str, str_len, len, "csi=%d ", dci->csi_request); + // Antenna ports + if (!cfg->enable_transform_precoding && !cfg->pusch_dmrs_double) { + count += 3; + } else { + ERROR("Not implemented"); + return 0; + } - return len; + // SRS request - 2 bits + count += 2; + + // CSI request - 0, 1, 2, 3, 4, 5, or 6 bits + count += SRSRAN_MIN(6, cfg->report_trigger_size); + + // CBG transmission information - 0, 2, 4, 6, or 8 bits + count += cfg->pusch_nof_cbg; + + // PTRS-DMRS association - 0 or 2 bits + if ((!cfg->pusch_ptrs && !cfg->enable_transform_precoding) || cfg->enable_transform_precoding || + cfg->nof_ul_layers <= 1) { + count += 0; + } else { + count += 3; + } + + // beta_offset indicator – 0 or 2 bits + if (cfg->pusch_dynamic_betas) { + count += 2; + } + + // DMRS sequence initialization - 0 or 1 bit + if (!cfg->enable_transform_precoding) { + count += 1; + } + + // UL-SCH indicator – 1 bit + count += 1; + + return count; } -int srsran_dci_nr_format_1_0_pack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - const srsran_dci_dl_nr_t* dci, - srsran_dci_msg_nr_t* msg) +static int dci_nr_format_0_1_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg) { - uint8_t* y = msg->payload; - srsran_rnti_type_t rnti_type = msg->rnti_type; + // TODO! - if (carrier == NULL) { - return SRSRAN_ERROR; - } + return SRSRAN_SUCCESS; +} + +static int dci_nr_format_0_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci) +{ + // TODO! + + return SRSRAN_SUCCESS; +} + +static uint32_t dci_nr_format_1_0_sizeof(uint32_t N_DL_BWP_RB, srsran_rnti_type_t rnti_type) +{ + uint32_t count = 0; // Identifier for DCI formats – 1 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - *y = 1; - y++; + count += 1; } if (rnti_type == srsran_rnti_type_p) { // Short Messages Indicator – 2 bits - srsran_bit_unpack(dci->smi, &y, 2); + count += 2; // Short Messages – 8 bits - srsran_bit_unpack(dci->sm, &y, 8); + count += 8; } // Frequency domain resource assignment - int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB); if (N < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } - srsran_bit_unpack(dci->freq_domain_assigment, &y, N); + count += N; // Time domain resource assignment – 4 bits - srsran_bit_unpack(dci->time_domain_assigment, &y, 4); + count += 4; // VRB-to-PRB mapping – 1 bit - srsran_bit_unpack(dci->vrb_to_prb_mapping, &y, 1); + count += 1; // Modulation and coding scheme – 5 bits - srsran_bit_unpack(dci->mcs, &y, 5); + count += 5; // TB scaling – 2 bits if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) { - srsran_bit_unpack(dci->tb_scaling, &y, 2); + count += 2; } // New data indicator – 1 bit if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->ndi, &y, 1); + count += 1; } // Redundancy version – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->rv, &y, 2); + count += 2; } // HARQ process number – 4 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->pid, &y, 4); + count += 4; } // System information indicator – 1 bit if (rnti_type == srsran_rnti_type_si) { - srsran_bit_unpack(dci->sii, &y, 1); + count += 1; } // Downlink assignment index – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->dai, &y, 2); + count += 2; } // TPC command for scheduled PUCCH – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->tpc, &y, 2); + count += 2; } // PUCCH resource indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->pucch_resource, &y, 3); + count += 3; } // PDSCH-to-HARQ_feedback timing indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - srsran_bit_unpack(dci->harq_feedback, &y, 3); + count += 3; } // Reserved bits ... if (rnti_type == srsran_rnti_type_p) { // ... – 6 bits - srsran_bit_unpack(dci->reserved, &y, 6); + count += 2; } else if (rnti_type == srsran_rnti_type_si) { // ... – 15 bits - srsran_bit_unpack(dci->reserved, &y, 15); + count += 15; } else if (rnti_type == srsran_rnti_type_ra) { // ... – 16 bits - srsran_bit_unpack(dci->reserved, &y, 16); - } - - msg->nof_bits = srsran_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type); - if (msg->nof_bits != y - msg->payload) { - ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload)); - return SRSRAN_ERROR; + count += 16; } - return SRSRAN_SUCCESS; + return count; } -int srsran_dci_nr_format_1_0_unpack(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_dci_msg_nr_t* msg, - srsran_dci_dl_nr_t* dci) +static int dci_nr_format_1_0_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg) { - uint8_t* y = msg->payload; - srsran_rnti_type_t rnti_type = msg->rnti_type; - - // Copy DCI MSG fields - dci->location = msg->location; - dci->search_space = msg->search_space; - dci->coreset_id = msg->coreset_id; - dci->rnti_type = msg->rnti_type; - dci->rnti = msg->rnti; - dci->format = msg->format; - - if (msg->nof_bits != srsran_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type)) { - ERROR("Invalid number of bits %d, expected %d", - msg->nof_bits, - srsran_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type)); - return SRSRAN_ERROR; - } + uint8_t* y = msg->payload; + srsran_rnti_type_t rnti_type = msg->ctx.rnti_type; + srsran_search_space_type_t ss_type = dci->ctx.ss_type; + uint32_t N_DL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type) + ? (q->cfg.coreset0_bw == 0) ? q->cfg.bwp_dl_initial_bw : q->cfg.coreset0_bw + : q->cfg.bwp_dl_active_bw; // Identifier for DCI formats – 1 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - // The value of this bit field is always set to 1, indicating a DL DCI format - if (*(y++) != 1) { - ERROR("Wrond DCI format"); - return SRSRAN_ERROR; - } + *y = 1; + y++; } if (rnti_type == srsran_rnti_type_p) { // Short Messages Indicator – 2 bits - dci->smi = srsran_bit_pack(&y, 2); + srsran_bit_unpack(dci->smi, &y, 2); // Short Messages – 8 bits - dci->sm = srsran_bit_pack(&y, 8); + srsran_bit_unpack(dci->sm, &y, 8); } // Frequency domain resource assignment - int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB); if (N < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } - dci->freq_domain_assigment = srsran_bit_pack(&y, N); + srsran_bit_unpack(dci->freq_domain_assigment, &y, N); // Time domain resource assignment – 4 bits - dci->time_domain_assigment = srsran_bit_pack(&y, 4); + srsran_bit_unpack(dci->time_domain_assigment, &y, 4); // VRB-to-PRB mapping – 1 bit - dci->vrb_to_prb_mapping = srsran_bit_pack(&y, 1); + srsran_bit_unpack(dci->vrb_to_prb_mapping, &y, 1); // Modulation and coding scheme – 5 bits - dci->mcs = srsran_bit_pack(&y, 5); + srsran_bit_unpack(dci->mcs, &y, 5); // TB scaling – 2 bits if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) { - dci->tb_scaling = srsran_bit_pack(&y, 2); + srsran_bit_unpack(dci->tb_scaling, &y, 2); } // New data indicator – 1 bit if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->ndi = srsran_bit_pack(&y, 1); + srsran_bit_unpack(dci->ndi, &y, 1); } // Redundancy version – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) { - dci->rv = srsran_bit_pack(&y, 2); + srsran_bit_unpack(dci->rv, &y, 2); } // HARQ process number – 4 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->pid = srsran_bit_pack(&y, 4); + srsran_bit_unpack(dci->pid, &y, 4); } // System information indicator – 1 bit if (rnti_type == srsran_rnti_type_si) { - dci->sii = srsran_bit_pack(&y, 1); + srsran_bit_unpack(dci->sii, &y, 1); } // Downlink assignment index – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->dai = srsran_bit_pack(&y, 2); + srsran_bit_unpack(dci->dai, &y, 2); } // TPC command for scheduled PUCCH – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->tpc = srsran_bit_pack(&y, 2); + srsran_bit_unpack(dci->tpc, &y, 2); } // PUCCH resource indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->pucch_resource = srsran_bit_pack(&y, 3); + srsran_bit_unpack(dci->pucch_resource, &y, 3); } // PDSCH-to-HARQ_feedback timing indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - dci->harq_feedback = srsran_bit_pack(&y, 3); + srsran_bit_unpack(dci->harq_feedback, &y, 3); } // Reserved bits ... if (rnti_type == srsran_rnti_type_p) { // ... – 6 bits - dci->reserved = srsran_bit_pack(&y, 6); + srsran_bit_unpack(dci->reserved, &y, 6); } else if (rnti_type == srsran_rnti_type_si) { // ... – 15 bits - dci->reserved = srsran_bit_pack(&y, 15); + srsran_bit_unpack(dci->reserved, &y, 15); } else if (rnti_type == srsran_rnti_type_ra) { // ... – 16 bits - dci->reserved = srsran_bit_pack(&y, 16); + srsran_bit_unpack(dci->reserved, &y, 16); } - if (msg->nof_bits != y - msg->payload) { - ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload)); + msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_1_0); + uint32_t nof_bits = (uint32_t)(y - msg->payload); + if (msg->nof_bits != nof_bits) { + ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, nof_bits); return SRSRAN_ERROR; } return SRSRAN_SUCCESS; } -int srsran_dci_nr_format_1_0_sizeof(const srsran_carrier_nr_t* carrier, - const srsran_coreset_t* coreset, - srsran_rnti_type_t rnti_type) +static int dci_nr_format_1_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci) { - int count = 0; + uint8_t* y = msg->payload; + srsran_rnti_type_t rnti_type = msg->ctx.rnti_type; + srsran_search_space_type_t ss_type = msg->ctx.ss_type; + uint32_t N_DL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type) + ? (q->cfg.coreset0_bw == 0) ? q->cfg.bwp_dl_initial_bw : q->cfg.coreset0_bw + : q->cfg.bwp_dl_active_bw; + + uint32_t nof_bits = srsran_dci_nr_size(q, ss_type, srsran_dci_format_nr_1_0); + if (msg->nof_bits != nof_bits) { + ERROR("Invalid number of bits %d, expected %d", msg->nof_bits, nof_bits); + return SRSRAN_ERROR; + } // Identifier for DCI formats – 1 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 1; + // The value of this bit field is always set to 1, indicating a DL DCI format + if (*(y++) != 1) { + ERROR("Wrond DCI format"); + return SRSRAN_ERROR; + } } if (rnti_type == srsran_rnti_type_p) { // Short Messages Indicator – 2 bits - count += 2; + dci->smi = srsran_bit_pack(&y, 2); // Short Messages – 8 bits - count += 8; + dci->sm = srsran_bit_pack(&y, 8); } // Frequency domain resource assignment - int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB); if (N < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } - count += N; + dci->freq_domain_assigment = srsran_bit_pack(&y, N); // Time domain resource assignment – 4 bits - count += 4; + dci->time_domain_assigment = srsran_bit_pack(&y, 4); // VRB-to-PRB mapping – 1 bit - count += 1; + dci->vrb_to_prb_mapping = srsran_bit_pack(&y, 1); // Modulation and coding scheme – 5 bits - count += 5; + dci->mcs = srsran_bit_pack(&y, 5); // TB scaling – 2 bits if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) { - count += 2; + dci->tb_scaling = srsran_bit_pack(&y, 2); } // New data indicator – 1 bit if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 1; + dci->ndi = srsran_bit_pack(&y, 1); } // Redundancy version – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) { - count += 2; + dci->rv = srsran_bit_pack(&y, 2); } // HARQ process number – 4 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 4; + dci->pid = srsran_bit_pack(&y, 4); } // System information indicator – 1 bit if (rnti_type == srsran_rnti_type_si) { - count += 1; + dci->sii = srsran_bit_pack(&y, 1); } // Downlink assignment index – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 2; + dci->dai = srsran_bit_pack(&y, 2); } // TPC command for scheduled PUCCH – 2 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 2; + dci->tpc = srsran_bit_pack(&y, 2); } // PUCCH resource indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 3; + dci->pucch_resource = srsran_bit_pack(&y, 3); } // PDSCH-to-HARQ_feedback timing indicator – 3 bits if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { - count += 3; + dci->harq_feedback = srsran_bit_pack(&y, 3); } // Reserved bits ... if (rnti_type == srsran_rnti_type_p) { // ... – 6 bits - count += 2; + dci->reserved = srsran_bit_pack(&y, 6); } else if (rnti_type == srsran_rnti_type_si) { // ... – 15 bits - count += 15; + dci->reserved = srsran_bit_pack(&y, 15); } else if (rnti_type == srsran_rnti_type_ra) { // ... – 16 bits - count += 16; + dci->reserved = srsran_bit_pack(&y, 16); } - return count; + if (msg->nof_bits != y - msg->payload) { + ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload)); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; } static int dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len) { - uint32_t len = 0; + uint32_t len = 0; + srsran_rnti_type_t rnti_type = dci->ctx.rnti_type; // Print format len = srsran_print_check( - str, str_len, len, "rnti=%04x L=%d cce=%d dci=1_0 ", dci->rnti, dci->location.L, dci->location.ncce); + str, str_len, len, "rnti=%04x L=%d cce=%d dci=1_0 ", dci->ctx.rnti, dci->ctx.location.L, dci->ctx.location.ncce); - if (dci->rnti_type == srsran_rnti_type_p) { + if (rnti_type == srsran_rnti_type_p) { len = srsran_print_check(str, str_len, len, "smi=%d sm=%d ", dci->smi, dci->sm); } @@ -763,64 +773,504 @@ static int dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* str, ui len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs); // TB scaling – 2 bits - if (dci->rnti_type == srsran_rnti_type_p || dci->rnti_type == srsran_rnti_type_ra) { + if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) { len = srsran_print_check(str, str_len, len, "tb_scaling=%d ", dci->tb_scaling); } // New data indicator – 1 bit - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "ndi=%d ", dci->ndi); } // Redundancy version – 2 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_si || - dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "rv=%d ", dci->rv); } // HARQ process number – 4 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "harq_id=%d ", dci->harq_feedback); } // System information indicator – 1 bit - if (dci->rnti_type == srsran_rnti_type_si) { + if (rnti_type == srsran_rnti_type_si) { len = srsran_print_check(str, str_len, len, "sii=%d ", dci->sii); } // Downlink assignment index – 2 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "dai=%d ", dci->dai); } // TPC command for scheduled PUCCH – 2 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "pucch_tpc=%d ", dci->tpc); } // PUCCH resource indicator – 3 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "pucch_res=%d ", dci->pucch_resource); } // PDSCH-to-HARQ_feedback timing indicator – 3 bits - if (dci->rnti_type == srsran_rnti_type_c || dci->rnti_type == srsran_rnti_type_tc) { + if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) { len = srsran_print_check(str, str_len, len, "harq_feedback=%d ", dci->harq_feedback); } // Reserved bits ... - if (dci->rnti_type == srsran_rnti_type_p || dci->rnti_type == srsran_rnti_type_si || - dci->rnti_type == srsran_rnti_type_ra) { + if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_ra) { len = srsran_print_check(str, str_len, len, "reserved=0x%x ", dci->reserved); } return len; } +static uint32_t dci_nr_format_1_1_sizeof(const srsran_dci_cfg_nr_t* cfg, srsran_rnti_type_t rnti_type) +{ + int count = 0; + + if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) { + ERROR("Invalid RNTI (%s) for format 1_1", srsran_rnti_type_str(rnti_type)); + return SRSRAN_ERROR; + } + + // Identifier for DCI formats – 1 bits + count += 1; + + // Carrier indicator – 0 or 3 bits + count += (int)SRSRAN_MIN(cfg->carrier_indicator_size, 3); + + // Bandwidth part indicator – 0, 1 or 2 bits + count += (int)SRSRAN_MIN(dci_nr_bwp_id_size(cfg->nof_ul_bwp), 2); + + // Frequency domain resource assignment + count += dci_nr_freq_resource_size(cfg->pdsch_alloc_type, cfg->nof_rb_groups, cfg->bwp_dl_active_bw); + + // Time domain resource assignment – 0, 1, 2, 3, or 4 bits + count += dci_nr_time_res_size(cfg->nof_dl_time_res); + + // VRB-to-PRB mapping – 0 or 1 + if (cfg->pdsch_alloc_type != srsran_resource_alloc_type0 && cfg->pdsch_inter_prb_to_prb) { + count += 1; + } + + // PRB bundling size indicator – 0 or 1 bits + // ... not implemented + + // Rate matching indicator – 0, 1, or 2 bits + if (cfg->pdsch_rm_pattern1) { + count += 1; + } + if (cfg->pdsch_rm_pattern2) { + count += 1; + } + + // ZP CSI-RS trigger - 0, 1, or 2 bits + count += (int)CEIL_LOG2(cfg->nof_aperiodic_zp + 1); + + // For transport block 1: + // Modulation and coding scheme – 5 bits + count += 5; + + // New data indicator – 1 bit + count += 1; + + // Redundancy version – 2 bits + count += 2; + + // For transport block 2: + if (cfg->pdsch_2cw) { + // Modulation and coding scheme – 5 bits + count += 5; + + // New data indicator – 1 bit + count += 1; + + // Redundancy version – 2 bits + count += 2; + } + + // HARQ process number – 4 bits + count += 4; + + // Downlink assignment index (dynamic HARQ-ACK codebook only) + if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_dynamic) { + if (cfg->multiple_scell) { + count += 4; + } else { + count += 2; + } + } + + // TPC command for scheduled PUCCH – 2 bits + count += 2; + + // PDSCH-to-HARQ_feedback timing indicator – 0, 1, 2, or 3 bits + count += (int)CEIL_LOG2(cfg->nof_dl_to_ul_ack); + + // Antenna port(s) – 4, 5, or 6 bits + count += 4; + if (cfg->pdsch_dmrs_type2) { + count++; + } + if (cfg->pdsch_dmrs_double) { + count++; + } + + // Transmission configuration indication – 0 or 3 bits + if (cfg->pdsch_tci) { + count += 3; + } + + // SRS request – 2 or 3 bits + count += 2; + if (cfg->enable_sul) { + count++; + } + + // CBG transmission information (CBGTI) – 0, 2, 4, 6, or 8 bits + count += cfg->pdsch_nof_cbg; + + // CBG flushing out information (CBGFI) – 0 or 1 bit + if (cfg->pdsch_cbg_flush) { + count += 1; + } + + // DMRS sequence initialization – 1 bit + count += 1; + + return count; +} + +static int dci_nr_format_1_1_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg) +{ + // TODO! + + return SRSRAN_SUCCESS; +} + +static int dci_nr_format_1_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci) +{ + // TODO! + + return SRSRAN_SUCCESS; +} + +int srsran_dci_nr_set_cfg(srsran_dci_nr_t* q, const srsran_dci_cfg_nr_t* cfg) +{ + // Reset current setup + SRSRAN_MEM_ZERO(q, srsran_dci_nr_t, 1); + + // Copy configuration + q->cfg = *cfg; + + // Step 0 + // - Determine DCI format 0_0 monitored in a common search space according to clause 7.3.1.1.1 where N_UL_BWP_RB is + // given by the size of the initial UL bandwidth part. + uint32_t size_dci_0_0_common = dci_nr_format_0_0_sizeof(cfg->bwp_ul_initial_bw, cfg); + + // - Determine DCI format 1_0 monitored in a common search space according to clause 7.3.1.2.1 where N_DL_BWP_RB given + // by: + // - the size of CORESET 0 if CORESET 0 is configured for the cell; and + // - the size of initial DL bandwidth part if CORESET 0 is not configured for the cell. + uint32_t size_dci_1_0_common = dci_nr_format_1_0_sizeof(cfg->bwp_dl_initial_bw, srsran_rnti_type_c); + if (cfg->coreset0_bw != 0) { + size_dci_1_0_common = dci_nr_format_1_0_sizeof(cfg->coreset0_bw, srsran_rnti_type_c); + } + + // - If DCI format 0_0 is monitored in common search space and if the number of information bits in the DCI format 0_0 + // prior to padding is less than the payload size of the DCI format 1_0 monitored in common search space for + // scheduling the same serving cell, a number of zero padding bits are generated for the DCI format 0_0 until the + // payload size equals that of the DCI format 1_0. + if (cfg->monitor_common_0_0 && size_dci_0_0_common < size_dci_1_0_common) { + q->dci_0_0_common_padd = size_dci_1_0_common - size_dci_0_0_common; + } else { + q->dci_0_0_common_padd = 0; + } + + // - If DCI format 0_0 is monitored in common search space and if the number of information bits in the DCI format 0_0 + // prior to truncation is larger than the payload size of the DCI format 1_0 monitored in common search space for + // scheduling the same serving cell, the bitwidth of the frequency domain resource assignment field in the DCI format + // 0_0 is reduced by truncating the first few most significant bits such that the size of DCI format 0_0 equals the + // size of the DCI format 1_0. + if (cfg->monitor_common_0_0 && size_dci_0_0_common > size_dci_1_0_common) { + q->dci_0_0_common_trunc = size_dci_0_0_common - size_dci_1_0_common; + } else { + q->dci_0_0_common_trunc = 0; + } + + q->dci_0_0_and_1_0_common_size = SRSRAN_MAX(size_dci_1_0_common, DCI_NR_MIN_SIZE); + + // Step 1 + // - Determine DCI format 0_0 monitored in a UE-specific search space according to clause 7.3.1.1.1 where N_UL_BWP_RB + // is the size of the active UL bandwidth part. + uint32_t size_dci_0_0_ue = dci_nr_format_0_0_sizeof(cfg->bwp_ul_active_bw, cfg); + + // - Determine DCI format 1_0 monitored in a UE-specific search space according to clause 7.3.1.2.1 where N_DL_BWP_RB + // is the size of the active DL bandwidth part. + uint32_t size_dci_1_0_ue = dci_nr_format_1_0_sizeof(cfg->bwp_dl_active_bw, srsran_rnti_type_c); + + // - For a UE configured with supplementaryUplink in ServingCellConfig in a cell, if PUSCH is configured to be + // transmitted on both the SUL and the non-SUL of the cell and if the number of information bits in DCI format 0_0 in + // UE-specific search space for the SUL is not equal to the number of information bits in DCI format 0_0 in + // UE-specific search space for the non-SUL, a number of zero padding bits are generated for the smaller DCI format + // 0_0 until the payload size equals that of the larger DCI format 0_0. + // ... Not implemented + + // - If DCI format 0_0 is monitored in UE-specific search space and if the number of information bits in the DCI + // format 0_0 prior to padding is less than the payload size of the DCI format 1_0 monitored in UE-specific search + // space for scheduling the same serving cell, a number of zero padding bits are generated for the DCI format 0_0 + // until the payload size equals that of the DCI format 1_0. + if (cfg->monitor_0_0_and_1_0 && size_dci_0_0_ue < size_dci_1_0_ue) { + q->dci_0_0_ue_padd = size_dci_1_0_ue - size_dci_0_0_ue; + } + + // - If DCI format 1_0 is monitored in UE-specific search space and if the number of information bits in the DCI + // format 1_0 prior to padding is less than the payload size of the DCI format 0_0 monitored in UE-specific search + // space for scheduling the same serving cell, zeros shall be appended to the DCI format 1_0 until the payload size + // equals that of the DCI format 0_0 + if (cfg->monitor_0_0_and_1_0 && size_dci_1_0_ue < size_dci_0_0_ue) { + q->dci_1_0_ue_padd = size_dci_0_0_ue - size_dci_1_0_ue; + } + + q->dci_0_0_and_1_0_ue_size = SRSRAN_MAX(SRSRAN_MAX(size_dci_0_0_ue, size_dci_1_0_ue), DCI_NR_MIN_SIZE); + + // Step 2 + // For a UE configured with supplementaryUplink in ServingCellConfig in a cell, if PUSCH is configured to be + // transmitted on both the SUL and the non-SUL of the cell and if the number of information bits in format 0_1 for + // the SUL is not equal to the number of information bits in format 0_1 for the non-SUL, zeros shall be appended + // to smaller format 0_1 until the payload size equals that of the larger format 0_1. + // ... Not implemented + + uint32_t size_dci_0_1 = dci_nr_format_0_1_sizeof(cfg, srsran_rnti_type_c); + uint32_t size_dci_1_1 = dci_nr_format_1_1_sizeof(cfg, srsran_rnti_type_c); + if (size_dci_0_1 == 0 || size_dci_1_1 == 0) { + return SRSRAN_ERROR; + } + + // If the size of DCI format 0_1 monitored in a UE-specific search space equals that of a DCI format 0_0/1_0 + // monitored in another UE-specific search space, one bit of zero padding shall be appended to DCI format 0_1. + if (size_dci_0_1 == q->dci_0_0_and_1_0_ue_size) { + q->dci_0_1_padd++; + } + + // If the size of DCI format 1_1 monitored in a UE-specific search space equals that of a DCI format 0_0/1_0 + // monitored in another UE-specific search space, one bit of zero padding shall be appended to DCI format 1_1. + if (size_dci_1_1 == q->dci_0_0_and_1_0_ue_size) { + q->dci_1_1_padd++; + } + + q->dci_0_1_size = size_dci_0_1 + q->dci_0_1_padd; + q->dci_1_1_size = size_dci_1_1 + q->dci_1_1_padd; + + // Step 3 + // If both of the following conditions are fulfilled the size alignment procedure is complete: + // - the total number of different DCI sizes configured to monitor is no more than 4 for the cell + // - the total number of different DCI sizes with C-RNTI configured to monitor is no more than 3 for the cell + // ... Current code is compatible with only possible sizes! + + return SRSRAN_SUCCESS; +} + +uint32_t srsran_dci_nr_size(const srsran_dci_nr_t* q, srsran_search_space_type_t ss_type, srsran_dci_format_nr_t format) +{ + // Check input + if (q == NULL) { + return 0; + } + + // For common search space, only formats 0_0 and 1_0 + if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)) { + return q->dci_0_0_and_1_0_common_size; + } + + // DCI formats 0_0 and 1_0 in UE-specific + if (format == srsran_dci_format_nr_0_0 || format == srsran_dci_format_nr_1_0) { + return q->dci_0_0_and_1_0_ue_size; + } + + // DCI format 0_1 in UE-specific + if (format == srsran_dci_format_nr_0_1) { + return q->dci_0_1_size; + } + + // DCI format 1_1 in UE-specific + if (format == srsran_dci_format_nr_1_1) { + return q->dci_1_1_size; + } + + // Not implemented + return 0; +} + +bool srsran_dci_nr_valid_direction(const srsran_dci_msg_nr_t* dci) +{ + // Check pointer + if (dci == NULL) { + return false; + } + + // UL direction + uint32_t expected_direction = 0; + + // Set DL direction if is DL grant + if (dci->ctx.format == srsran_dci_format_nr_1_0 || dci->ctx.format == srsran_dci_format_nr_1_1) { + expected_direction = 1; + } + + // The format bit is only present for these RNTI + if (dci->ctx.rnti_type == srsran_rnti_type_c || dci->ctx.rnti_type == srsran_rnti_type_tc) { + return dci->payload[0] == expected_direction; + } + + // For other RNTI types, assume always DL on 1_0 + return (dci->ctx.format == srsran_dci_format_nr_1_0); +} + +static int dci_nr_rar_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg) +{ + ERROR("Not implemented"); + return SRSRAN_ERROR; +} + +static int dci_nr_rar_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci) +{ + if (msg == NULL || dci == NULL) { + return SRSRAN_ERROR; + } + + uint8_t* y = msg->payload; + + // Copy DCI MSG fields + dci->ctx = msg->ctx; + + // Frequency hopping flag - 1 bit + dci->freq_hopping_flag = srsran_bit_pack(&y, 1); + + // PUSCH frequency resource allocation - 14 bits + dci->freq_domain_assigment = srsran_bit_pack(&y, 14); + + // PUSCH time resource allocation - 4 bits + dci->time_domain_assigment = srsran_bit_pack(&y, 4); + + // MCS -4 bits + dci->mcs = srsran_bit_pack(&y, 4); + + // TPC command for PUSCH - 3 bits + dci->tpc = srsran_bit_pack(&y, 3); + + // CSI request - 1 bits + dci->csi_request = srsran_bit_pack(&y, 3); + + return SRSRAN_SUCCESS; +} + +static int dci_nr_rar_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + // Print format + len = srsran_print_check(str, str_len, len, "rnti=%04x dci=rar ", dci->ctx.rnti); + + // Frequency hopping flag + len = srsran_print_check(str, str_len, len, "hop=%d ", dci->freq_hopping_flag); + + // PUSCH frequency resource allocation + len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment); + + // PUSCH time resource allocation + len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment); + + // Modulation and coding scheme + len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs); + + // TPC command for scheduled PUSCH + len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc); + + // CSI request + len = srsran_print_check(str, str_len, len, "csi=%d ", dci->csi_request); + + return len; +} + +int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg) +{ + // Copy DCI MSG fields + msg->ctx = dci->ctx; + + // Pack DCI + switch (msg->ctx.format) { + case srsran_dci_format_nr_1_0: + return dci_nr_format_1_0_pack(q, dci, msg); + case srsran_dci_format_nr_1_1: + return dci_nr_format_1_1_pack(q, dci, msg); + default: + ERROR("Unsupported DCI format %d", msg->ctx.format); + } + + return SRSRAN_ERROR; +} + +int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci) +{ + // Copy DCI MSG fields + dci->ctx = msg->ctx; + + // Pack DCI + switch (msg->ctx.format) { + case srsran_dci_format_nr_1_0: + return dci_nr_format_1_0_unpack(q, msg, dci); + case srsran_dci_format_nr_1_1: + return dci_nr_format_1_1_unpack(q, msg, dci); + default: + ERROR("Unsupported DCI format %d", msg->ctx.format); + } + return SRSRAN_ERROR; +} + +int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg) +{ + // Copy DCI MSG fields + msg->ctx = dci->ctx; + + // Pack DCI + switch (msg->ctx.format) { + case srsran_dci_format_nr_0_0: + return dci_nr_format_0_0_pack(q, dci, msg); + case srsran_dci_format_nr_0_1: + return dci_nr_format_0_1_pack(q, dci, msg); + case srsran_dci_format_nr_rar: + return dci_nr_rar_pack(q, dci, msg); + default: + ERROR("Unsupported DCI format %d", msg->ctx.format); + } + + return SRSRAN_ERROR; +} + +int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci) +{ + // Copy DCI MSG fields + dci->ctx = msg->ctx; + + // Pack DCI + switch (msg->ctx.format) { + case srsran_dci_format_nr_0_0: + return dci_nr_format_0_0_unpack(q, msg, dci); + case srsran_dci_format_nr_0_1: + return dci_nr_format_0_1_unpack(q, msg, dci); + case srsran_dci_format_nr_rar: + return dci_nr_rar_unpack(q, msg, dci); + default: + ERROR("Unsupported DCI format %d", msg->ctx.format); + } + return SRSRAN_ERROR; +} + int srsran_dci_ul_nr_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len) { // Pack DCI - switch (dci->format) { + switch (dci->ctx.format) { case srsran_dci_format_nr_0_0: return dci_nr_format_0_0_to_str(dci, str, str_len); case srsran_dci_format_nr_rar: @@ -834,7 +1284,7 @@ int srsran_dci_ul_nr_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t s int srsran_dci_dl_nr_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len) { // Pack DCI - switch (dci->format) { + switch (dci->ctx.format) { case srsran_dci_format_nr_1_0: return dci_nr_format_1_0_to_str(dci, str, str_len); default:; // Do nothing diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index c29946e50..a0f18c106 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -324,11 +324,11 @@ static uint32_t pdcch_nr_cp(const srsran_pdcch_nr_t* q, static uint32_t pdcch_nr_c_init(const srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_msg) { - uint32_t n_id = (dci_msg->search_space == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) + uint32_t n_id = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) ? q->coreset.dmrs_scrambling_id : q->carrier.id; - uint32_t n_rnti = (dci_msg->search_space == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) - ? dci_msg->rnti + uint32_t n_rnti = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) + ? dci_msg->ctx.rnti : 0U; return ((n_rnti << 16U) + n_id) & 0x7fffffffU; } @@ -345,10 +345,10 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_ } // Calculate... - q->K = dci_msg->nof_bits + 24U; // Payload size including CRC - q->M = (1U << dci_msg->location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE - q->E = q->M * 2; // Number of Rate-Matched bits - uint32_t cinit = pdcch_nr_c_init(q, dci_msg); // Pseudo-random sequence initiation + q->K = dci_msg->nof_bits + 24U; // Payload size including CRC + q->M = (1U << dci_msg->ctx.location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE + q->E = q->M * 2; // Number of Rate-Matched bits + uint32_t cinit = pdcch_nr_c_init(q, dci_msg); // Pseudo-random sequence initiation // Get polar code if (srsran_polar_code_get(&q->code, q->K, q->E, 9U) < SRSRAN_SUCCESS) { @@ -371,7 +371,7 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_ // Unpack RNTI uint8_t unpacked_rnti[16] = {}; uint8_t* ptr = unpacked_rnti; - srsran_bit_unpack(dci_msg->rnti, &ptr, 16); + srsran_bit_unpack(dci_msg->ctx.rnti, &ptr, 16); // Scramble CRC with RNTI srsran_vec_xor_bbb(unpacked_rnti, &c[q->K - 16], &c[q->K - 16], 16); @@ -412,7 +412,7 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_ srsran_mod_modulate(&q->modem_table, q->f, q->symbols, q->E); // Put symbols in grid - uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true); + uint32_t m = pdcch_nr_cp(q, &dci_msg->ctx.location, slot_symbols, q->symbols, true); if (q->M != m) { ERROR("Unmatch number of RE (%d != %d)", m, q->M); return SRSRAN_ERROR; @@ -449,9 +449,9 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q, } // Calculate... - q->K = dci_msg->nof_bits + 24U; // Payload size including CRC - q->M = (1U << dci_msg->location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE - q->E = q->M * 2; // Number of Rate-Matched bits + q->K = dci_msg->nof_bits + 24U; // Payload size including CRC + q->M = (1U << dci_msg->ctx.location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE + q->E = q->M * 2; // Number of Rate-Matched bits // Check number of estimates is correct if (ce->nof_re != q->M) { @@ -466,7 +466,7 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q, PDCCH_INFO_RX("K=%d; E=%d; M=%d; n=%d;", q->K, q->E, q->M, q->code.n); // Get symbols from grid - uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false); + uint32_t m = pdcch_nr_cp(q, &dci_msg->ctx.location, slot_symbols, q->symbols, false); if (q->M != m) { ERROR("Unmatch number of RE (%d != %d)", m, q->M); return SRSRAN_ERROR; @@ -546,7 +546,7 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q, // Unpack RNTI uint8_t unpacked_rnti[16] = {}; uint8_t* ptr = unpacked_rnti; - srsran_bit_unpack(dci_msg->rnti, &ptr, 16); + srsran_bit_unpack(dci_msg->ctx.rnti, &ptr, 16); // De-Scramble CRC with RNTI srsran_vec_xor_bbb(unpacked_rnti, &c[q->K - 16], &c[q->K - 16], 16); diff --git a/lib/src/phy/phch/ra_dl_nr.c b/lib/src/phy/phch/ra_dl_nr.c index b8419d08b..cbc52d656 100644 --- a/lib/src/phy/phch/ra_dl_nr.c +++ b/lib/src/phy/phch/ra_dl_nr.c @@ -62,7 +62,7 @@ int srsran_ra_dl_nr_time_default_A(uint32_t m, srsran_dmrs_sch_typeA_pos_t dmrs_ return SRSRAN_ERROR_INVALID_INPUTS; } - if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) { + if (m >= SRSRAN_MAX_NOF_TIME_RA) { ERROR("m (%d) is out-of-range", m); return SRSRAN_ERROR_INVALID_INPUTS; } @@ -89,10 +89,10 @@ int srsran_ra_dl_nr_time_default_A(uint32_t m, srsran_dmrs_sch_typeA_pos_t dmrs_ srsran_sch_mapping_type_B}; grant->mapping = pdsch_mapping_lut[m]; - static uint32_t S_pos2[SRSRAN_MAX_NOF_DL_ALLOCATION] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8}; - static uint32_t L_pos2[SRSRAN_MAX_NOF_DL_ALLOCATION] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; - static uint32_t S_pos3[SRSRAN_MAX_NOF_DL_ALLOCATION] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8}; - static uint32_t L_pos3[SRSRAN_MAX_NOF_DL_ALLOCATION] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; + static uint32_t S_pos2[SRSRAN_MAX_NOF_TIME_RA] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8}; + static uint32_t L_pos2[SRSRAN_MAX_NOF_TIME_RA] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; + static uint32_t S_pos3[SRSRAN_MAX_NOF_TIME_RA] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8}; + static uint32_t L_pos3[SRSRAN_MAX_NOF_TIME_RA] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; // Select start symbol (S) and length (L) switch (dmrs_typeA_pos) { @@ -132,7 +132,7 @@ int srsran_ra_dl_nr_time(const srsran_sch_hl_cfg_nr_t* cfg, return SRSRAN_ERROR_INVALID_INPUTS; } - if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) { + if (m >= SRSRAN_MAX_NOF_TIME_RA) { ERROR("m (%d) is out-of-range", m); return SRSRAN_ERROR_INVALID_INPUTS; } @@ -177,7 +177,7 @@ int srsran_ra_dl_nr_time(const srsran_sch_hl_cfg_nr_t* cfg, srsran_ra_dl_nr_time_default_A(m, cfg->typeA_pos, grant); } } else { - ERROR("Unhandled case"); + ERROR("Unhandled case %s, ss_type=%d", srsran_rnti_type_str(rnti_type), ss_type); } // Validate S and L parameters @@ -264,7 +264,7 @@ int srsran_ra_dl_nr_freq(const srsran_carrier_nr_t* carrier, } // RA scheme - if (dci_dl->format == srsran_dci_format_nr_1_0) { + if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) { // when the scheduling grant is received with DCI format 1_0 , then downlink resource allocation type 1 is used. return ra_helper_freq_type1(carrier->nof_prb, dci_dl->freq_domain_assigment, grant); } diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 53caf96c3..20dc9dabd 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -653,9 +653,9 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, { // 5.2.1.1 Resource allocation in time domain if (srsran_ra_dl_nr_time(pdsch_hl_cfg, - dci_dl->rnti_type, - dci_dl->search_space, - dci_dl->coreset_id, + dci_dl->ctx.rnti_type, + dci_dl->ctx.ss_type, + dci_dl->ctx.coreset_id, dci_dl->time_domain_assigment, pdsch_grant) < SRSRAN_SUCCESS) { ERROR("Error computing time domain resource allocation"); @@ -672,9 +672,9 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, // ... pdsch_grant->nof_layers = 1; - pdsch_grant->dci_format = dci_dl->format; - pdsch_grant->rnti = dci_dl->rnti; - pdsch_grant->rnti_type = dci_dl->rnti_type; + pdsch_grant->dci_format = dci_dl->ctx.format; + pdsch_grant->rnti = dci_dl->ctx.rnti; + pdsch_grant->rnti_type = dci_dl->ctx.rnti_type; pdsch_grant->tb[0].rv = dci_dl->rv; // 5.1.4 PDSCH resource mapping @@ -705,7 +705,8 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, srsran_sch_grant_nr_t* pu ? pusch_hl_cfg->dmrs_typeA.present : pusch_hl_cfg->dmrs_typeB.present; - if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || !dedicated_dmrs_present) { + if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || pusch_grant->dci_format == srsran_dci_format_nr_rar || + !dedicated_dmrs_present) { if (pusch_grant->mapping == srsran_sch_mapping_type_A) { // Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2; @@ -734,13 +735,13 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, srsran_sch_grant_nr_t* pu } // Set number of DMRS CDM groups without data - if (pusch_grant->dci_format == srsran_dci_format_nr_0_0) { + if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || pusch_grant->dci_format == srsran_dci_format_nr_rar) { if (srsran_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(cfg, pusch_grant) < SRSRAN_SUCCESS) { ERROR("Error loading number of DMRS CDM groups"); return SRSRAN_ERROR; } } else { - ERROR("Invalid case"); + ERROR("DCI format not implemented %s", srsran_dci_format_nr_string(pusch_grant->dci_format)); return SRSRAN_ERROR; } @@ -761,9 +762,9 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, { // 5.2.1.1 Resource allocation in time domain if (srsran_ra_ul_nr_time(pusch_hl_cfg, - dci_ul->rnti_type, - dci_ul->search_space, - dci_ul->coreset_id, + dci_ul->ctx.rnti_type, + dci_ul->ctx.ss_type, + dci_ul->ctx.coreset_id, dci_ul->time_domain_assigment, pusch_grant) < SRSRAN_SUCCESS) { ERROR("Error computing time domain resource allocation"); @@ -780,9 +781,9 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, // ... pusch_grant->nof_layers = 1; - pusch_grant->dci_format = dci_ul->format; - pusch_grant->rnti = dci_ul->rnti; - pusch_grant->rnti_type = dci_ul->rnti_type; + pusch_grant->dci_format = dci_ul->ctx.format; + pusch_grant->rnti = dci_ul->ctx.rnti; + pusch_grant->rnti_type = dci_ul->ctx.rnti_type; // 5.1.6.2 DM-RS reception procedure if (ra_ul_dmrs(pusch_hl_cfg, pusch_grant, pusch_cfg) < SRSRAN_SUCCESS) { diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 8960f2903..02e1a541b 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -132,7 +132,7 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg, return SRSRAN_ERROR_INVALID_INPUTS; } - if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) { + if (m >= SRSRAN_MAX_NOF_TIME_RA) { ERROR("m (%d) is out-of-range", m); return SRSRAN_ERROR_INVALID_INPUTS; } @@ -142,12 +142,12 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg, // Row 1 if (cfg->nof_common_time_ra == 0) { srsran_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant); - } else if (m < SRSRAN_MAX_NOF_DL_ALLOCATION && m < cfg->nof_common_time_ra) { + } else if (m < SRSRAN_MAX_NOF_TIME_RA && m < cfg->nof_common_time_ra) { ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); } else { ERROR("Time domain resource selection (m=%d) exceeds the maximum value (%d)", m, - SRSRAN_MIN(cfg->nof_common_time_ra, SRSRAN_MAX_NOF_DL_ALLOCATION)); + SRSRAN_MIN(cfg->nof_common_time_ra, SRSRAN_MAX_NOF_TIME_RA)); } } else if ((rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_mcs_c || rnti_type == srsran_rnti_type_tc || rnti_type == srsran_rnti_type_cs) && @@ -155,7 +155,7 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg, // Row 2 if (cfg->nof_common_time_ra == 0) { srsran_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant); - } else if (m < SRSRAN_MAX_NOF_DL_ALLOCATION) { + } else if (m < SRSRAN_MAX_NOF_TIME_RA) { ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); } } else if ((rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_mcs_c || @@ -374,12 +374,12 @@ int srsran_ra_ul_nr_freq(const srsran_carrier_nr_t* carrier, } // RA scheme - if (dci_ul->format == srsran_dci_format_nr_0_0) { + if (dci_ul->ctx.format == srsran_dci_format_nr_0_0 || dci_ul->ctx.format == srsran_dci_format_nr_rar) { // when the scheduling grant is received with DCI format 1_0 , then downlink resource allocation type 1 is used. return ra_helper_freq_type1(carrier->nof_prb, dci_ul->freq_domain_assigment, grant); } - ERROR("Only DCI Format 0_0 is supported"); + ERROR("Unhandled DCI Format %s", srsran_dci_format_nr_string(dci_ul->ctx.format)); return SRSRAN_ERROR; } diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 66e83a79b..22f2d654d 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -616,6 +616,10 @@ endif(RF_FOUND) # NR ######################################################################## +add_executable(dci_nr_test dci_nr_test.c) +target_link_libraries(dci_nr_test srsran_phy) +add_nr_test(dci_nr_test dci_nr_test) + add_executable(pucch_nr_test pucch_nr_test.c) target_link_libraries(pucch_nr_test srsran_phy) add_nr_test(pucch_nr_test pucch_nr_test) diff --git a/lib/src/phy/phch/test/dci_nr_test.c b/lib/src/phy/phch/test/dci_nr_test.c new file mode 100644 index 000000000..2d8ed5d1b --- /dev/null +++ b/lib/src/phy/phch/test/dci_nr_test.c @@ -0,0 +1,53 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/common/test_common.h" +#include "srsran/phy/phch/dci_nr.h" + +static int test_52prb() +{ + // Default configuration with all options disabled + srsran_dci_cfg_nr_t cfg = {}; + + // Set bandwidths + cfg.coreset0_bw = 0; + cfg.bwp_dl_initial_bw = 52; + cfg.bwp_dl_active_bw = 52; + cfg.bwp_ul_initial_bw = 52; + cfg.bwp_ul_active_bw = 52; + + // Enable all monitoring + cfg.monitor_common_0_0 = true; + cfg.monitor_0_0_and_1_0 = true; + cfg.monitor_0_1_and_1_1 = true; + + // Configure DCI + srsran_dci_nr_t dci = {}; + TESTASSERT(srsran_dci_nr_set_cfg(&dci, &cfg) == SRSRAN_SUCCESS); + + // Check DCI sizes + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_common_3, srsran_dci_format_nr_0_0) == 39); + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_common_3, srsran_dci_format_nr_1_0) == 39); + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_0) == 39); + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_0) == 39); + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_1) == 28); + TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_1) == 26); + + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + TESTASSERT(test_52prb() == SRSRAN_SUCCESS); + + return SRSRAN_SUCCESS; +} diff --git a/lib/src/phy/phch/test/pdcch_nr_test.c b/lib/src/phy/phch/test/pdcch_nr_test.c index 23e6da6d5..afe6562e8 100644 --- a/lib/src/phy/phch/test/pdcch_nr_test.c +++ b/lib/src/phy/phch/test/pdcch_nr_test.c @@ -43,8 +43,8 @@ static int test(srsran_pdcch_nr_t* tx, // Encode PDCCH TESTASSERT(srsran_pdcch_nr_encode(tx, dci_msg_tx, grid) == SRSRAN_SUCCESS); - enc_time[dci_msg_tx->location.L].time_us += tx->meas_time_us; - enc_time[dci_msg_tx->location.L].count++; + enc_time[dci_msg_tx->ctx.location.L].time_us += tx->meas_time_us; + enc_time[dci_msg_tx->ctx.location.L].count++; // Init Rx MSG srsran_pdcch_nr_res_t res = {}; @@ -54,8 +54,8 @@ static int test(srsran_pdcch_nr_t* tx, // Decode PDCCH TESTASSERT(srsran_pdcch_nr_decode(rx, grid, ce, &dci_msg_rx, &res) == SRSRAN_SUCCESS); - dec_time[dci_msg_tx->location.L].time_us += rx->meas_time_us; - dec_time[dci_msg_tx->location.L].count++; + dec_time[dci_msg_tx->ctx.location.L].time_us += rx->meas_time_us; + dec_time[dci_msg_tx->ctx.location.L].count++; // Assert TESTASSERT(res.evm < 0.01f); @@ -142,8 +142,27 @@ int main(int argc, char** argv) } for (coreset.duration = SRSRAN_CORESET_DURATION_MIN; coreset.duration <= SRSRAN_CORESET_DURATION_MAX; coreset.duration++) { - srsran_search_space_t search_space = {}; - search_space.type = srsran_search_space_type_ue; + srsran_search_space_t search_space = {}; + search_space.type = srsran_search_space_type_ue; + search_space.formats[search_space.nof_formats++] = srsran_dci_format_nr_0_0; + search_space.formats[search_space.nof_formats++] = srsran_dci_format_nr_1_0; + + srsran_dci_cfg_nr_t dci_cfg = {}; + dci_cfg.coreset0_bw = 0; + dci_cfg.bwp_dl_initial_bw = carrier.nof_prb; + dci_cfg.bwp_dl_active_bw = carrier.nof_prb; + dci_cfg.bwp_ul_initial_bw = carrier.nof_prb; + dci_cfg.bwp_ul_active_bw = carrier.nof_prb; + dci_cfg.monitor_common_0_0 = true; + dci_cfg.monitor_0_0_and_1_0 = true; + dci_cfg.monitor_0_1_and_1_1 = true; + + // Precompute DCI sizes + srsran_dci_nr_t dci = {}; + if (srsran_dci_nr_set_cfg(&dci, &dci_cfg) < SRSRAN_SUCCESS) { + ERROR("Error setting DCI configuratio"); + goto clean_exit; + } if (srsran_pdcch_nr_set_carrier(&pdcch_tx, &carrier, &coreset) < SRSRAN_SUCCESS) { ERROR("Error setting carrier"); @@ -185,11 +204,11 @@ int main(int argc, char** argv) for (uint32_t ncce_idx = 0; ncce_idx < n; ncce_idx++) { // Init MSG srsran_dci_msg_nr_t dci_msg = {}; - dci_msg.format = srsran_dci_format_nr_1_0; - dci_msg.rnti_type = srsran_rnti_type_c; - dci_msg.location.L = aggregation_level; - dci_msg.location.ncce = dci_locations[ncce_idx]; - dci_msg.nof_bits = srsran_dci_nr_format_1_0_sizeof(&carrier, &coreset, dci_msg.rnti_type); + dci_msg.ctx.format = srsran_dci_format_nr_1_0; + dci_msg.ctx.rnti_type = srsran_rnti_type_c; + dci_msg.ctx.location.L = aggregation_level; + dci_msg.ctx.location.ncce = dci_locations[ncce_idx]; + dci_msg.nof_bits = srsran_dci_nr_size(&dci, search_space.type, srsran_dci_format_nr_1_0); // Generate random payload for (uint32_t i = 0; i < dci_msg.nof_bits; i++) { diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index a2254a896..2c90fccb5 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -165,7 +165,9 @@ int srsran_ue_dl_nr_set_carrier(srsran_ue_dl_nr_t* q, const srsran_carrier_nr_t* return SRSRAN_SUCCESS; } -int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr_pdcch_cfg_t* cfg) +int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, + const srsran_pdcch_cfg_nr_t* cfg, + const srsran_dci_cfg_nr_t* dci_cfg) { if (q == NULL || cfg == NULL) { return SRSRAN_ERROR_INVALID_INPUTS; @@ -176,13 +178,22 @@ int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr // iterate over all possible CORESET and initialise/update the present ones for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; i++) { - if (cfg->coreset_present[i]) { - if (srsran_dmrs_pdcch_estimator_init(&q->dmrs_pdcch[i], &q->carrier, &cfg->coreset[i]) < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } + // Skip CORESET if not present + if (!cfg->coreset_present[i]) { + continue; + } + + // Initialise estimator for the CORESET + if (srsran_dmrs_pdcch_estimator_init(&q->dmrs_pdcch[i], &q->carrier, &cfg->coreset[i]) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; } } + // Configure DCI sizes + if (srsran_dci_nr_set_cfg(&q->dci, dci_cfg) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; } @@ -220,28 +231,28 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q, return SRSRAN_ERROR; } SRSRAN_MEM_ZERO(pdcch_info, srsran_ue_dl_nr_pdcch_info_t, 1); - pdcch_info->coreset_id = dci_msg->coreset_id; - pdcch_info->ss_id = dci_msg->search_space; - pdcch_info->location = dci_msg->location; + pdcch_info->dci_ctx = dci_msg->ctx; + pdcch_info->nof_bits = dci_msg->nof_bits; srsran_dmrs_pdcch_measure_t* m = &pdcch_info->measure; // Measures the PDCCH transmission DMRS - if (srsran_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &dci_msg->location, m) < SRSRAN_SUCCESS) { - ERROR("Error getting measure location L=%d, ncce=%d", dci_msg->location.L, dci_msg->location.ncce); + srsran_dci_location_t location = dci_msg->ctx.location; + if (srsran_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &location, m) < SRSRAN_SUCCESS) { + ERROR("Error getting measure location L=%d, ncce=%d", location.L, location.ncce); return SRSRAN_ERROR; } // If measured correlation is invalid, early return if (!isnormal(m->norm_corr)) { - INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;", dci_msg->location.L, dci_msg->location.ncce); + INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;", location.L, location.ncce); return SRSRAN_SUCCESS; } // Compare EPRE with threshold if (m->epre_dBfs < q->pdcch_dmrs_epre_thr) { INFO("Discarded PDCCH candidate L=%d;ncce=%d; EPRE is too weak (%.1f<%.1f);", - dci_msg->location.L, - dci_msg->location.ncce, + location.L, + location.ncce, m->epre_dBfs, q->pdcch_dmrs_epre_thr); return SRSRAN_SUCCESS; @@ -250,8 +261,8 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q, // Compare DMRS correlation with threshold if (m->norm_corr < q->pdcch_dmrs_corr_thr) { INFO("Discarded PDCCH candidate L=%d;ncce=%d; Correlation is too low (%.1f<%.1f); EPRE=%+.2f; RSRP=%+.2f;", - dci_msg->location.L, - dci_msg->location.ncce, + location.L, + location.ncce, m->norm_corr, q->pdcch_dmrs_corr_thr, m->epre_dBfs, @@ -260,7 +271,7 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q, } // Extract PDCCH channel estimates - if (srsran_dmrs_pdcch_get_ce(&q->dmrs_pdcch[coreset_id], &dci_msg->location, q->pdcch_ce) < SRSRAN_SUCCESS) { + if (srsran_dmrs_pdcch_get_ce(&q->dmrs_pdcch[coreset_id], &location, q->pdcch_ce) < SRSRAN_SUCCESS) { ERROR("Error extracting PDCCH DMRS"); return SRSRAN_ERROR; } @@ -293,12 +304,15 @@ static bool find_dci_msg(srsran_dci_msg_nr_t* dci_msg, uint32_t nof_dci_msg, srs return found; } -static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q, - const srsran_slot_cfg_t* slot_cfg, - const srsran_search_space_t* search_space, - uint16_t rnti, - srsran_rnti_type_t rnti_type) +static int ue_dl_nr_find_dci_ss(srsran_ue_dl_nr_t* q, + const srsran_slot_cfg_t* slot_cfg, + const srsran_search_space_t* search_space, + uint16_t rnti, + srsran_rnti_type_t rnti_type) { + uint32_t dci_sizes[SRSRAN_DCI_NR_MAX_NOF_SIZES] = {}; + uint32_t dci_sizes_count = 0; + // Select CORESET uint32_t coreset_id = search_space->coreset_id; if (coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET || !q->cfg.coreset_present[coreset_id]) { @@ -313,81 +327,124 @@ static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q, return SRSRAN_ERROR; } - // Hard-coded values - srsran_dci_format_nr_t dci_format = srsran_dci_format_nr_1_0; + // Iterate all possible formats + for (uint32_t format_idx = 0; format_idx < SRSRAN_MIN(search_space->nof_formats, SRSRAN_DCI_FORMAT_NR_COUNT); + format_idx++) { + srsran_dci_format_nr_t dci_format = search_space->formats[format_idx]; - // Calculate number of DCI bits - int dci_nof_bits = srsran_dci_nr_format_1_0_sizeof(&q->carrier, coreset, rnti_type); - if (dci_nof_bits <= SRSRAN_SUCCESS) { - ERROR("Error DCI size"); - return SRSRAN_ERROR; - } - - // Iterate all possible aggregation levels - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && q->dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; - L++) { - // Calculate possible PDCCH DCI candidates - uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; - int nof_candidates = srsran_pdcch_nr_locations_coreset( - coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), candidates); - if (nof_candidates < SRSRAN_SUCCESS) { - ERROR("Error calculating DCI candidate location"); + // Calculate number of DCI bits + uint32_t dci_nof_bits = srsran_dci_nr_size(&q->dci, search_space->type, dci_format); + if (dci_nof_bits == 0) { + ERROR("Error DCI size"); return SRSRAN_ERROR; } - // Iterate over the candidates - for (int ncce_idx = 0; ncce_idx < nof_candidates && q->dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; ncce_idx++) { - // Set DCI context - srsran_dci_msg_nr_t dci_msg = {}; - dci_msg.location.L = L; - dci_msg.location.ncce = candidates[ncce_idx]; - dci_msg.search_space = search_space->type; - dci_msg.coreset_id = search_space->coreset_id; - dci_msg.rnti_type = rnti_type; - dci_msg.rnti = rnti; - dci_msg.format = dci_format; - dci_msg.nof_bits = (uint32_t)dci_nof_bits; - - // Find and decode PDCCH transmission in the given ncce - srsran_pdcch_nr_res_t res = {}; - if (ue_dl_nr_find_dci_ncce(q, &dci_msg, &res, coreset_id) < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; + // Skip DCI format if the size was already searched for the search space + bool skip = false; + for (uint32_t i = 0; i < dci_sizes_count && !skip; i++) { + if (dci_nof_bits == dci_sizes[i]) { + skip = true; } + } + if (skip) { + continue; + } - // If the CRC was not match, move to next candidate - if (!res.crc) { - continue; + // Append size + if (dci_sizes_count >= SRSRAN_DCI_NR_MAX_NOF_SIZES) { + ERROR("Exceed maximum number of DCI sizes"); + return SRSRAN_ERROR; + } + dci_sizes[dci_sizes_count++] = dci_nof_bits; + + // Iterate all possible aggregation levels + for (uint32_t L = 0; + L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && q->dl_dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; + L++) { + // Calculate possible PDCCH DCI candidates + uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; + int nof_candidates = srsran_pdcch_nr_locations_coreset( + coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), candidates); + if (nof_candidates < SRSRAN_SUCCESS) { + ERROR("Error calculating DCI candidate location"); + return SRSRAN_ERROR; } - // Detect if the DCI was a format 0_0 - if (!srsran_dci_nr_format_1_0_valid(&dci_msg)) { - // Change grant format to 0_0 - dci_msg.format = srsran_dci_format_nr_0_0; + // Iterate over the candidates + for (int ncce_idx = 0; ncce_idx < nof_candidates && q->dl_dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; ncce_idx++) { + // Build DCI context + srsran_dci_ctx_t ctx = {}; + ctx.location.L = L; + ctx.location.ncce = candidates[ncce_idx]; + ctx.ss_type = search_space->type; + ctx.coreset_id = search_space->coreset_id; + ctx.rnti_type = rnti_type; + ctx.rnti = rnti; + ctx.format = dci_format; + + // Build DCI message + srsran_dci_msg_nr_t dci_msg = {}; + dci_msg.ctx = ctx; + dci_msg.nof_bits = (uint32_t)dci_nof_bits; + + // Find and decode PDCCH transmission in the given ncce + srsran_pdcch_nr_res_t res = {}; + if (ue_dl_nr_find_dci_ncce(q, &dci_msg, &res, coreset_id) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } - // If the pending UL grant list is full or has the dci message, keep moving - if (q->pending_ul_dci_count >= SRSRAN_MAX_DCI_MSG_NR || - find_dci_msg(q->pending_ul_dci_msg, q->pending_ul_dci_count, &dci_msg)) { + // If the CRC was not match, move to next candidate + if (!res.crc) { continue; } - // Save the grant in the pending UL grant list - q->pending_ul_dci_msg[q->pending_ul_dci_count] = dci_msg; - q->pending_ul_dci_count++; + // Detect if the DCI is the right direction + if (!srsran_dci_nr_valid_direction(&dci_msg)) { + // Change grant format direction + switch (dci_msg.ctx.format) { + case srsran_dci_format_nr_0_0: + dci_msg.ctx.format = srsran_dci_format_nr_1_0; + break; + case srsran_dci_format_nr_0_1: + dci_msg.ctx.format = srsran_dci_format_nr_1_1; + break; + case srsran_dci_format_nr_1_0: + dci_msg.ctx.format = srsran_dci_format_nr_0_0; + break; + case srsran_dci_format_nr_1_1: + dci_msg.ctx.format = srsran_dci_format_nr_0_1; + break; + default: + continue; + } + } - // Move to next candidate - continue; - } + // If UL grant, enqueue in UL list + if (dci_msg.ctx.format == srsran_dci_format_nr_0_0 || dci_msg.ctx.format == srsran_dci_format_nr_0_1) { + // If the pending UL grant list is full or has the dci message, keep moving + if (q->ul_dci_count >= SRSRAN_MAX_DCI_MSG_NR || find_dci_msg(q->ul_dci_msg, q->ul_dci_count, &dci_msg)) { + continue; + } - // Check if the grant exists already in the message list - if (find_dci_msg(q->dci_msg, q->dci_msg_count, &dci_msg)) { - // The same DCI is in the list, keep moving - continue; - } + // Save the grant in the pending UL grant list + q->ul_dci_msg[q->ul_dci_count] = dci_msg; + q->ul_dci_count++; - INFO("Found DCI in L=%d,ncce=%d", dci_msg.location.L, dci_msg.location.ncce); - // Append DCI message into the list - q->dci_msg[q->dci_msg_count] = dci_msg; - q->dci_msg_count++; + // Move to next candidate + continue; + } + + // Check if the grant exists already in the DL list + if (find_dci_msg(q->dl_dci_msg, q->dl_dci_msg_count, &dci_msg)) { + // The same DCI is in the list, keep moving + continue; + } + + INFO("Found DCI in L=%d,ncce=%d", dci_msg.ctx.location.L, dci_msg.ctx.location.ncce); + // Append DCI message into the list + q->dl_dci_msg[q->dl_dci_msg_count] = dci_msg; + q->dl_dci_msg_count++; + } } } @@ -410,27 +467,27 @@ int srsran_ue_dl_nr_find_dl_dci(srsran_ue_dl_nr_t* q, nof_dci_msg = SRSRAN_MIN(nof_dci_msg, SRSRAN_MAX_DCI_MSG_NR); // Reset grant and blind search information counters - q->dci_msg_count = 0; + q->dl_dci_msg_count = 0; q->pdcch_info_count = 0; // If the UE looks for a RAR and RA search space is provided, search for it if (q->cfg.ra_search_space_present && rnti_type == srsran_rnti_type_ra) { // Find DCIs in the RA search space - int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type); + int ret = ue_dl_nr_find_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type); if (ret < SRSRAN_SUCCESS) { ERROR("Error searching RAR DCI"); return SRSRAN_ERROR; } } else { // Iterate all possible common and UE search spaces - for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE && q->dci_msg_count < nof_dci_msg; i++) { + for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE && q->dl_dci_msg_count < nof_dci_msg; i++) { // Skip search space if not present if (!q->cfg.search_space_present[i]) { continue; } // Find DCIs in the selected search space - int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type); + int ret = ue_dl_nr_find_dci_ss(q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type); if (ret < SRSRAN_SUCCESS) { ERROR("Error searching DCI"); return SRSRAN_ERROR; @@ -439,10 +496,12 @@ int srsran_ue_dl_nr_find_dl_dci(srsran_ue_dl_nr_t* q, } // Convert found DCI messages into DL grants - uint32_t dci_msg_count = SRSRAN_MIN(nof_dci_msg, q->dci_msg_count); + uint32_t dci_msg_count = SRSRAN_MIN(nof_dci_msg, q->dl_dci_msg_count); for (uint32_t i = 0; i < dci_msg_count; i++) { - const srsran_coreset_t* coreset = &q->cfg.coreset[q->dci_msg[i].coreset_id]; - srsran_dci_nr_format_1_0_unpack(&q->carrier, coreset, &q->dci_msg[i], &dci_dl_list[i]); + if (srsran_dci_nr_dl_unpack(&q->dci, &q->dl_dci_msg[i], &dci_dl_list[i]) < SRSRAN_SUCCESS) { + ERROR("Error unpacking grant %d;", i); + return SRSRAN_ERROR; + } } return (int)dci_msg_count; @@ -463,15 +522,14 @@ int srsran_ue_dl_nr_find_ul_dci(srsran_ue_dl_nr_t* q, } // Get DCI messages from the pending list - for (uint32_t i = 0; i < q->pending_ul_dci_count && count < nof_dci_msg; i++) { - srsran_dci_msg_nr_t* dci_msg = &q->pending_ul_dci_msg[i]; + for (uint32_t i = 0; i < q->ul_dci_count && count < nof_dci_msg; i++) { + srsran_dci_msg_nr_t* dci_msg = &q->ul_dci_msg[i]; - if (dci_msg->rnti_type != rnti_type || dci_msg->rnti != rnti) { + if (dci_msg->ctx.rnti_type != rnti_type || dci_msg->ctx.rnti != rnti) { continue; } - const srsran_coreset_t* coreset = &q->cfg.coreset[dci_msg->coreset_id]; - if (srsran_dci_nr_format_0_0_unpack(&q->carrier, coreset, dci_msg, &dci_ul_list[count]) < SRSRAN_SUCCESS) { + if (srsran_dci_nr_ul_unpack(&q->dci, dci_msg, &dci_ul_list[count]) < SRSRAN_SUCCESS) { ERROR("Unpacking DCI 0_0"); continue; } @@ -479,7 +537,7 @@ int srsran_ue_dl_nr_find_ul_dci(srsran_ue_dl_nr_t* q, } // Reset pending UL grant list - q->pending_ul_dci_count = 0; + q->ul_dci_count = 0; return count; } @@ -638,7 +696,7 @@ static int ue_dl_nr_gen_ack_type2(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg, int ue_dl_nr_pdsch_k1(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg, const srsran_dci_dl_nr_t* dci_dl) { // For DCI format 1_0, the PDSCH-to-HARQ_feedback timing indicator field values map to {1, 2, 3, 4, 5, 6, 7, 8} - if (dci_dl->format == srsran_dci_format_nr_1_0) { + if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) { return (int)dci_dl->harq_feedback + 1; } @@ -668,10 +726,10 @@ int srsran_ue_dl_nr_pdsch_ack_resource(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg } // Fill PDSCH resource - pdsch_ack_resource->dci_format_1_1 = (dci_dl->format == srsran_dci_format_nr_1_1); + pdsch_ack_resource->dci_format_1_1 = (dci_dl->ctx.format == srsran_dci_format_nr_1_1); pdsch_ack_resource->k1 = k1; pdsch_ack_resource->v_dai_dl = dci_dl->dai; - pdsch_ack_resource->rnti = dci_dl->rnti; + pdsch_ack_resource->rnti = dci_dl->ctx.rnti; pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource; return SRSRAN_SUCCESS; @@ -687,14 +745,14 @@ int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg, } // According TS 38.213 9.1.2 Type-1 HARQ-ACK codebook determination - if (cfg->pdsch_harq_ack_codebook == srsran_pdsch_harq_ack_codebook_semi_static) { + if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_semi_static) { // This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = semi-static. ERROR("Type-1 HARQ-ACK codebook determination is NOT implemented"); return SRSRAN_ERROR; } // According TS 38.213 9.1.3 Type-2 HARQ-ACK codebook determination - if (cfg->pdsch_harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic) { + if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic) { // This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = dynamic. return ue_dl_nr_gen_ack_type2(cfg, ack_info, uci_data); } diff --git a/lib/test/asn1/rrc_nr_utils_test.cc b/lib/test/asn1/rrc_nr_utils_test.cc index ea71a2f14..6ca70f121 100644 --- a/lib/test/asn1/rrc_nr_utils_test.cc +++ b/lib/test/asn1/rrc_nr_utils_test.cc @@ -110,7 +110,7 @@ int make_phy_harq_ack_cfg_test() srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg; TESTASSERT(make_phy_harq_ack_cfg(phys_cell_group_cfg, &srsran_ue_dl_nr_harq_ack_cfg) == true); - TESTASSERT(srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic); + TESTASSERT(srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic); return SRSRAN_SUCCESS; } diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index 9434cc726..9af874437 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -118,12 +118,12 @@ static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl, // Hard-coded values srsran_dci_dl_nr_t dci_dl = {}; - dci_dl.rnti = pdsch_cfg.grant.rnti; - dci_dl.rnti_type = pdsch_cfg.grant.rnti_type; - dci_dl.format = srsran_dci_format_nr_1_0; - dci_dl.location = *dci_location; - dci_dl.search_space = search_space->type; - dci_dl.coreset_id = 1; + dci_dl.ctx.rnti = pdsch_cfg.grant.rnti; + dci_dl.ctx.rnti_type = pdsch_cfg.grant.rnti_type; + dci_dl.ctx.format = srsran_dci_format_nr_1_0; + dci_dl.ctx.location = *dci_location; + dci_dl.ctx.ss_type = search_space->type; + dci_dl.ctx.coreset_id = 1; dci_dl.freq_domain_assigment = 0; dci_dl.time_domain_assigment = 0; dci_dl.vrb_to_prb_mapping = 0; @@ -216,7 +216,7 @@ int main(int argc, char** argv) goto clean_exit; } - srsran_ue_dl_nr_pdcch_cfg_t pdcch_cfg = {}; + srsran_pdcch_cfg_nr_t pdcch_cfg = {}; // Configure CORESET srsran_coreset_t* coreset = &pdcch_cfg.coreset[1]; @@ -232,6 +232,9 @@ int main(int argc, char** argv) search_space->id = 0; search_space->coreset_id = 1; search_space->type = srsran_search_space_type_common_3; + search_space->formats[0] = srsran_dci_format_nr_0_0; + search_space->formats[1] = srsran_dci_format_nr_1_0; + search_space->nof_formats = 2; for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { search_space->nof_candidates[L] = srsran_pdcch_nr_max_candidates_coreset(coreset, L); } @@ -249,9 +252,14 @@ int main(int argc, char** argv) if (srsran_ue_dl_nr_set_carrier(&ue_dl, &carrier)) { ERROR("Error setting SCH NR carrier"); goto clean_exit; + goto clean_exit; } - if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg)) { + srsran_dci_cfg_nr_t dci_cfg = {}; + dci_cfg.bwp_dl_initial_bw = carrier.nof_prb; + dci_cfg.bwp_ul_initial_bw = carrier.nof_prb; + dci_cfg.monitor_common_0_0 = true; + if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg, &dci_cfg)) { ERROR("Error setting CORESET"); goto clean_exit; } @@ -261,7 +269,7 @@ int main(int argc, char** argv) goto clean_exit; } - if (srsran_enb_dl_nr_set_coreset(&enb_dl, coreset)) { + if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &pdcch_cfg, &dci_cfg)) { ERROR("Error setting CORESET"); goto clean_exit; } @@ -346,15 +354,21 @@ int main(int argc, char** argv) } // Compute PDCCH candidate locations - uint32_t L = 0; + uint32_t L = 1; uint32_t ncce_candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; - int nof_candidates = srsran_pdcch_nr_locations_coreset( - coreset, search_space, pdsch_cfg.grant.rnti, L, slot.idx, ncce_candidates); + int nof_candidates = srsran_pdcch_nr_locations_coreset(coreset, + search_space, + pdsch_cfg.grant.rnti, + L, + SRSRAN_SLOT_NR_MOD(carrier.numerology, slot.idx), + ncce_candidates); if (nof_candidates < SRSRAN_SUCCESS) { ERROR("Error getting PDCCH candidates"); goto clean_exit; } + srsran_vec_fprint_i(stdout, (int*)ncce_candidates, nof_candidates); + // Setup DCI location srsran_dci_location_t dci_location = {}; dci_location.ncce = ncce_candidates[0]; diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h index b61a84651..2226c83b8 100644 --- a/srsenb/hdr/phy/nr/cc_worker.h +++ b/srsenb/hdr/phy/nr/cc_worker.h @@ -14,8 +14,10 @@ #define SRSENB_NR_CC_WORKER_H #include "srsran/interfaces/gnb_interfaces.h" +#include "srsran/interfaces/rrc_nr_interface_types.h" #include "srsran/phy/enb/enb_dl_nr.h" #include "srsran/srslog/srslog.h" +#include "srsran/srsran.h" #include #include @@ -27,15 +29,11 @@ typedef struct { srsran_enb_dl_nr_args_t dl; } phy_nr_args_t; -typedef struct { - srsran_sch_hl_cfg_nr_t pdsch; -} phy_nr_cfg_t; - class phy_nr_state { public: - phy_nr_args_t args = {}; - phy_nr_cfg_t cfg = {}; + phy_nr_args_t args = {}; + srsran::phy_cfg_nr_t cfg = {}; phy_nr_state() { @@ -44,8 +42,7 @@ public: args.dl.nof_tx_antennas = 1; args.dl.pdsch.measure_evm = true; args.dl.pdsch.measure_time = true; - args.dl.pdsch.sch.disable_simd = true; - cfg.pdsch.sch_cfg.mcs_table = srsran_mcs_table_256qam; + args.dl.pdsch.sch.disable_simd = false; } }; diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc index 85f3827ea..b0fa34099 100644 --- a/srsenb/src/phy/nr/cc_worker.cc +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -60,7 +60,8 @@ bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier) coreset.freq_resources[0] = true; // Enable the bottom 6 PRB for PDCCH coreset.duration = 2; - if (srsran_enb_dl_nr_set_coreset(&enb_dl, &coreset) < SRSRAN_SUCCESS) { + srsran_dci_cfg_nr_t dci_cfg = phy_state->cfg.get_dci_cfg(*carrier); + if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { ERROR("Error setting coreset"); return false; } diff --git a/srsenb/src/phy/nr/sf_worker.cc b/srsenb/src/phy/nr/sf_worker.cc index a2723ed7b..fb134852a 100644 --- a/srsenb/src/phy/nr/sf_worker.cc +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -100,17 +100,17 @@ void sf_worker::work_imp() grants.pdsch[0].softbuffer_tx[0] = &softbuffer_tx; srsran_softbuffer_tx_reset(&softbuffer_tx); - grants.pdsch[0].dci.rnti = 0x1234; - grants.pdsch[0].dci.format = srsran_dci_format_nr_1_0; + grants.pdsch[0].dci.ctx.rnti = 0x1234; + grants.pdsch[0].dci.ctx.format = srsran_dci_format_nr_1_0; grants.pdsch[0].dci.freq_domain_assigment = 0x1FFF; grants.pdsch[0].dci.time_domain_assigment = 0; grants.pdsch[0].dci.mcs = 27; - grants.pdsch[0].dci.search_space = srsran_search_space_type_ue; - grants.pdsch[0].dci.coreset_id = 1; - grants.pdsch[0].dci.location.L = 0; - grants.pdsch[0].dci.location.ncce = 0; + grants.pdsch[0].dci.ctx.ss_type = srsran_search_space_type_ue; + grants.pdsch[0].dci.ctx.coreset_id = 1; + grants.pdsch[0].dci.ctx.location.L = 0; + grants.pdsch[0].dci.ctx.location.ncce = 0; for (auto& w : cc_workers) { w->work_dl(dl_cfg, grants); diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 8c3820f9b..80002d8b7 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -26,6 +26,7 @@ public: ~cc_worker(); bool set_carrier(const srsran_carrier_nr_t* carrier); + bool update_cfg(); void set_tti(uint32_t tti); cf_t* get_rx_buffer(uint32_t antenna_idx); @@ -38,6 +39,7 @@ public: int read_pdsch_d(cf_t* pdsch_d); private: + bool configured = false; srsran_slot_cfg_t dl_slot_cfg = {}; srsran_slot_cfg_t ul_slot_cfg = {}; uint32_t cc_idx = 0; diff --git a/srsue/hdr/phy/nr/sf_worker.h b/srsue/hdr/phy/nr/sf_worker.h index 60e6698d9..443fad74d 100644 --- a/srsue/hdr/phy/nr/sf_worker.h +++ b/srsue/hdr/phy/nr/sf_worker.h @@ -35,6 +35,7 @@ public: ~sf_worker() = default; bool set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* carrier_); + bool update_cfg(uint32_t cc_idx); /* Functions used by main PHY thread */ cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx); diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index fadaefaca..bd7862b87 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -70,11 +70,6 @@ bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier) return false; } - if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy->cfg.pdcch) < SRSRAN_SUCCESS) { - ERROR("Error setting carrier"); - return false; - } - if (srsran_ue_ul_nr_set_carrier(&ue_ul, carrier) < SRSRAN_SUCCESS) { ERROR("Error setting carrier"); return false; @@ -86,6 +81,20 @@ bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier) return true; } +bool cc_worker::update_cfg() +{ + srsran_dci_cfg_nr_t dci_cfg = phy->cfg.get_dci_cfg(phy->carrier); + + if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { + logger.error("Error setting NR PDCCH configuration"); + return false; + } + + configured = true; + + return true; +} + void cc_worker::set_tti(uint32_t tti) { dl_slot_cfg.idx = tti; @@ -129,7 +138,7 @@ void cc_worker::decode_pdcch_dl() int n_dl = srsran_ue_dl_nr_find_dl_dci(&ue_dl, &dl_slot_cfg, rnti.id, rnti.type, dci_rx.data(), (uint32_t)dci_rx.size()); if (n_dl < SRSRAN_SUCCESS) { - logger.error("Error decoding DL NR-PDCCH"); + logger.error("Error decoding DL NR-PDCCH for %s=0x%x", srsran_rnti_type_str(rnti.type), rnti.id); return; } @@ -149,14 +158,17 @@ void cc_worker::decode_pdcch_dl() if (logger.debug.enabled()) { for (uint32_t i = 0; i < ue_dl.pdcch_info_count; i++) { const srsran_ue_dl_nr_pdcch_info_t* info = &ue_dl.pdcch_info[i]; - logger.debug("PDCCH: crst_id=%d, ss_id=%d, ncce=%d, al=%d, EPRE=%+.2f, RSRP=%+.2f, corr=%.3f; crc=%s", - info->coreset_id, - info->ss_id, - info->location.ncce, - info->location.L, + logger.debug("PDCCH: rnti=0x%x, crst_id=%d, ss_type=%d, ncce=%d, al=%d, EPRE=%+.2f, RSRP=%+.2f, corr=%.3f; " + "nof_bits=%d; crc=%s;", + info->dci_ctx.rnti, + info->dci_ctx.coreset_id, + info->dci_ctx.ss_type, + info->dci_ctx.location.ncce, + info->dci_ctx.location.L, info->measure.epre_dBfs, info->measure.rsrp_dBfs, info->measure.norm_corr, + info->nof_bits, info->result.crc ? "OK" : "KO"); } } @@ -196,6 +208,11 @@ void cc_worker::decode_pdcch_ul() bool cc_worker::work_dl() { + // Do NOT process any DL if it is not configured + if (not configured) { + return true; + } + // Check if it is a DL slot, if not skip if (!srsran_tdd_nr_is_dl(&phy->cfg.tdd, 0, dl_slot_cfg.idx)) { return true; diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index 50dca8362..a354e2c35 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -45,6 +45,15 @@ bool sf_worker::set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* return cc_workers.at(cc_idx)->set_carrier(carrier_); } +bool sf_worker::update_cfg(uint32_t cc_idx) +{ + if (cc_idx >= cc_workers.size()) { + return false; + } + + return cc_workers[cc_idx]->update_cfg(); +} + cf_t* sf_worker::get_buffer(uint32_t cc_idx, uint32_t antenna_idx) { if (cc_idx >= cc_workers.size()) { diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index 606153250..6cc741846 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -94,16 +94,16 @@ int worker_pool::set_ul_grant(std::array pac { // Copy DCI bits and setup DCI context srsran_dci_msg_nr_t dci_msg = {}; - dci_msg.format = srsran_dci_format_nr_0_0; // MAC RAR grant shall be unpacked as DCI 0_0 format - dci_msg.rnti_type = rnti_type; - dci_msg.search_space = srsran_search_space_type_rar; // This indicates it is a MAC RAR - dci_msg.rnti = rnti; + dci_msg.ctx.format = srsran_dci_format_nr_rar; // MAC RAR grant shall be unpacked as DCI 0_0 format + dci_msg.ctx.rnti_type = rnti_type; + dci_msg.ctx.ss_type = srsran_search_space_type_rar; // This indicates it is a MAC RAR + dci_msg.ctx.rnti = rnti; dci_msg.nof_bits = SRSRAN_RAR_UL_GRANT_NBITS; srsran_vec_u8_copy(dci_msg.payload, packed_ul_grant.data(), SRSRAN_RAR_UL_GRANT_NBITS); srsran_dci_ul_nr_t dci_ul = {}; - if (srsran_dci_nr_rar_unpack(&dci_msg, &dci_ul) < SRSRAN_SUCCESS) { + if (srsran_dci_nr_ul_unpack(NULL, &dci_msg, &dci_ul) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } @@ -131,6 +131,13 @@ bool worker_pool::set_config(const srsran::phy_cfg_nr_t& cfg) return false; } + // Request workers to run any procedure related to configuration update + for (auto& w : workers) { + if (not w->update_cfg(0)) { + return false; + } + } + return true; } diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index fc9eb1221..e0a658e21 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -562,8 +562,8 @@ bool rrc_nr::apply_mac_cell_group(const mac_cell_group_cfg_s& mac_cell_group_cfg if (mac_cell_group_cfg.bsr_cfg_present) { logger.debug("Handling MAC BSR config"); srsran::bsr_cfg_nr_t bsr_cfg = {}; - bsr_cfg.periodic_timer = mac_cell_group_cfg.bsr_cfg.periodic_bsr_timer.to_number(); - bsr_cfg.retx_timer = mac_cell_group_cfg.bsr_cfg.retx_bsr_timer.to_number(); + bsr_cfg.periodic_timer = mac_cell_group_cfg.bsr_cfg.periodic_bsr_timer.to_number(); + bsr_cfg.retx_timer = mac_cell_group_cfg.bsr_cfg.retx_bsr_timer.to_number(); if (mac->set_config(bsr_cfg) != SRSRAN_SUCCESS) { return false; } @@ -610,7 +610,7 @@ bool rrc_nr::apply_sp_cell_init_dl_pdsch(const asn1::rrc_nr::pdsch_cfg_s& pdsch_ bool rrc_nr::apply_res_csi_report_cfg(const asn1::rrc_nr::csi_report_cfg_s& csi_report_cfg) { - uint32_t report_cfg_id = csi_report_cfg.report_cfg_id; + uint32_t report_cfg_id = csi_report_cfg.report_cfg_id; srsran_csi_hl_report_cfg_t srsran_csi_hl_report_cfg; if (make_phy_csi_report(csi_report_cfg, &srsran_csi_hl_report_cfg) == true) { phy_cfg.csi.reports[report_cfg_id] = srsran_csi_hl_report_cfg; @@ -692,7 +692,7 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com // phy_cfg.pdcch.ra_rnti = 0x16; //< Supposed to be deduced from PRACH configuration phy_cfg.pdcch.ra_search_space = phy_cfg.pdcch.search_space[pdcch_cfg_common.ra_search_space]; phy_cfg.pdcch.ra_search_space_present = true; - phy_cfg.pdcch.ra_search_space.type = srsran_search_space_type_common_3; + phy_cfg.pdcch.ra_search_space.type = srsran_search_space_type_common_1; } else { logger.warning("Search space %d not presenet for random access search space", pdcch_cfg_common.ra_search_space); @@ -748,7 +748,6 @@ bool rrc_nr::apply_ul_common_cfg(const asn1::rrc_nr::ul_cfg_common_s& ul_cfg_com if (ul_cfg_common.init_ul_bwp.rach_cfg_common_present) { if (ul_cfg_common.init_ul_bwp.rach_cfg_common.type() == setup_release_c::types_opts::setup) { rach_nr_cfg_t rach_nr_cfg = make_mac_rach_cfg(ul_cfg_common.init_ul_bwp.rach_cfg_common.setup()); - phy_cfg.pdcch.ra_rnti = ul_cfg_common.init_ul_bwp.rach_cfg_common.setup().rach_cfg_generic.prach_cfg_idx; mac->set_config(rach_nr_cfg); // Make the RACH configuration for PHY