diff --git a/lib/include/srslte/phy/common/phy_common_nr.h b/lib/include/srslte/phy/common/phy_common_nr.h index 4c02cc13f..664ca475f 100644 --- a/lib/include/srslte/phy/common/phy_common_nr.h +++ b/lib/include/srslte/phy/common/phy_common_nr.h @@ -143,6 +143,7 @@ typedef enum SRSLTE_API { srslte_search_space_type_common_2, ///< configured by pagingSearchSpace in PDCCH-ConfigCommon srslte_search_space_type_common_3, ///< configured by SearchSpace in PDCCH-Config with searchSpaceType = common srslte_search_space_type_ue, ///< configured by SearchSpace in PDCCH-Config with searchSpaceType = ue-Specific + srslte_search_space_rar ///< No search space associated, used for grants given by Random Access Response (RAR) } srslte_search_space_type_t; /** diff --git a/lib/include/srslte/phy/phch/dci_nr.h b/lib/include/srslte/phy/phch/dci_nr.h index eeb6c81ad..93e38a668 100644 --- a/lib/include/srslte/phy/phch/dci_nr.h +++ b/lib/include/srslte/phy/phch/dci_nr.h @@ -62,11 +62,44 @@ typedef struct SRSLTE_API { } srslte_dci_dl_nr_t; +typedef struct SRSLTE_API { + // Context information + uint16_t rnti; + srslte_rnti_type_t rnti_type; + srslte_dci_format_nr_t format; + srslte_dci_location_t location; + srslte_search_space_type_t search_space; + uint32_t coreset_id; + + // Common fields + uint32_t freq_domain_assigment; ///< Frequency domain resource assignment + uint32_t time_domain_assigment; ///< Time domain resource assignment + uint32_t freq_hopping_flag; ///< Frequency hopping flag + uint32_t mcs; ///< Modulation and coding scheme + uint32_t rv; ///< Redundancy version + uint32_t reserved; ///< Reserved bits + + // C-RNTI or CS-RNTI or MCS-C-RNTI + uint32_t ndi; ///< New data indicator + uint32_t pid; ///< HARQ process number + uint32_t tpc; ///< TPC command for scheduled PUCCH + uint32_t pucch_resource; ///< PUCCH resource indicator + uint32_t harq_feedback; ///< PDSCH-to-HARQ_feedback timing indicator + + // Frequency hopping + uint32_t frequency_offset; ///< frequency offset + +} srslte_dci_ul_nr_t; + SRSLTE_API int srslte_dci_nr_pack(const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset, const srslte_dci_dl_nr_t* dci, srslte_dci_msg_nr_t* msg); +SRSLTE_API int srslte_dci_nr_format_0_0_sizeof(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_rnti_type_t rnti_type); + SRSLTE_API SRSLTE_API int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset, srslte_rnti_type_t rnti_type); @@ -81,6 +114,6 @@ SRSLTE_API int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrie srslte_dci_msg_nr_t* msg, srslte_dci_dl_nr_t* dci); -SRSLTE_API int srslte_dci_nr_to_str(const srslte_dci_dl_nr_t* dci, char* str, uint32_t str_len); +SRSLTE_API int srslte_dci_dl_nr_to_str(const srslte_dci_dl_nr_t* dci, char* str, uint32_t str_len); #endif // SRSLTE_DCI_NR_H diff --git a/lib/include/srslte/phy/phch/phch_cfg_nr.h b/lib/include/srslte/phy/phch/phch_cfg_nr.h index b1a7a0953..6360e30a2 100644 --- a/lib/include/srslte/phy/phch/phch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/phch_cfg_nr.h @@ -82,21 +82,23 @@ typedef struct { } srslte_dmrs_sch_cfg_t; /** - * @brief flatten PDSCH time domain allocation parameters + * @brief Common flatten PDSCH and PUSCH time domain allocation parameters * @remark Described in TS 38.331 V15.10.0 Section PDSCH-TimeDomainResourceAllocationList + * @remark Described in TS 38.331 V15.10.0 Section PUSCH-TimeDomainResourceAllocationList */ typedef struct SRSLTE_API { - /// Slot offset between DCI and its scheduled PDSCH - uint32_t k0; + /// For PDSCH Slot offset between DCI and its scheduled PDSCH + /// For PUSCH parameter K2 + uint32_t k; - /// PDSCH mapping type + /// SCH mapping type srslte_sch_mapping_type_t mapping_type; /// An index giving valid combinations of start symbol and length (jointly encoded) as start and length indicator /// (SLIV). The network configures the field so that the allocation does not cross the slot boundary uint32_t sliv; -} srslte_pdsch_time_ra_t; +} srslte_sch_time_ra_t; /** * @brief PDSCH grant information provided by the Downlink Control Information (DCI) @@ -144,6 +146,8 @@ typedef struct SRSLTE_API { * @remark Described in TS 38.331 V15.10.0 Section PUSCH-Config */ typedef struct SRSLTE_API { + // Serving cell parameters + uint32_t scs_cfg; // Subcarrier spacing configuration srslte_dmrs_sch_typeA_pos_t typeA_pos; bool scrambling_id_present; @@ -157,28 +161,35 @@ typedef struct SRSLTE_API { uint32_t scrambling_id0; bool scrambling_id1_present; uint32_t scrambling_id1; + bool present; } dmrs_typeA; - bool dmrs_typeA_present; - srslte_dmrs_sch_cfg_t dmrs_typeB; - bool dmrs_typeB_present; + struct { + srslte_dmrs_sch_type_t type; + srslte_dmrs_sch_add_pos_t additional_pos; + srslte_dmrs_sch_len_t length; + bool scrambling_id0_present; + uint32_t scrambling_id0; + bool scrambling_id1_present; + uint32_t scrambling_id1; + bool present; + } dmrs_typeB; - srslte_pdsch_time_ra_t common_pdsch_time_ra[SRSLTE_MAX_NOF_DL_ALLOCATION]; - uint32_t nof_common_pdsch_time_ra; + srslte_sch_time_ra_t common_time_ra[SRSLTE_MAX_NOF_DL_ALLOCATION]; + uint32_t nof_common_time_ra; - srslte_pdsch_time_ra_t pdsch_time_ra[SRSLTE_MAX_NOF_DL_ALLOCATION]; - uint32_t nof_pdsch_time_ra; + srslte_sch_time_ra_t dedicated_time_ra[SRSLTE_MAX_NOF_DL_ALLOCATION]; + uint32_t nof_dedicated_time_ra; bool rbg_size_cfg_1; ///< RBG size configuration (1 or 2) srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters -} srslte_pdsch_cfg_nr_t; +} srslte_sch_hl_cfg_nr_t; /** * @brief Common NR-SCH (PDSCH and PUSCH for NR) configuration */ typedef struct SRSLTE_API { - bool scrambling_id_present; uint32_t scambling_id; // Identifier used to initialize data scrambling (0-1023) diff --git a/lib/include/srslte/phy/phch/ra_dl_nr.h b/lib/include/srslte/phy/phch/ra_dl_nr.h index 194525b1f..346cf796e 100644 --- a/lib/include/srslte/phy/phch/ra_dl_nr.h +++ b/lib/include/srslte/phy/phch/ra_dl_nr.h @@ -33,7 +33,7 @@ * @remark Defined by TS 38.214 V15.10.0 section 5.1.2.1.1 Determination of the resource allocation table to be used for * PDSCH * - * @param pdsch_cfg Flattened PDSCH configuration provided from higher layers + * @param cfg Flattened PDSCH configuration provided from higher layers * @param rnti_type Type of the RNTI of the corresponding DCI * @param ss_type Type of the SS for PDCCH * @param coreset_id CORESET identifier associated with the PDCCH transmission @@ -41,7 +41,7 @@ * @param[out] Provides grant pointer to fill * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code */ -SRSLTE_API int srslte_ra_dl_nr_time(const srslte_pdsch_cfg_nr_t* cfg, +SRSLTE_API int srslte_ra_dl_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, const srslte_rnti_type_t rnti_type, const srslte_search_space_type_t ss_type, const uint32_t coreset_id, @@ -84,9 +84,9 @@ SRSLTE_API int srslte_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(const * @param[out] grant Provides grant pointer to fill * @return SRSLTE_SUCCESS if the provided data is valid, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_ra_dl_nr_freq(const srslte_carrier_nr_t* carrier, - const srslte_pdsch_cfg_nr_t* cfg, - const srslte_dci_dl_nr_t* dci_dl, - srslte_sch_grant_nr_t* grant); +SRSLTE_API int srslte_ra_dl_nr_freq(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_dci_dl_nr_t* dci_dl, + srslte_sch_grant_nr_t* grant); #endif // SRSLTE_RA_DL_NR_H diff --git a/lib/include/srslte/phy/phch/ra_nr.h b/lib/include/srslte/phy/phch/ra_nr.h index 2f24d861f..8fded6bc5 100644 --- a/lib/include/srslte/phy/phch/ra_nr.h +++ b/lib/include/srslte/phy/phch/ra_nr.h @@ -95,10 +95,10 @@ SRSLTE_API int srslte_ra_nr_fill_tb(const srslte_sch_cfg_nr_t* pdsch_cfg, * @param pdsch_grant Generated PDSCH grant * @return 0 on success, -1 on error */ -SRSLTE_API int srslte_ra_dl_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, - const srslte_pdsch_cfg_nr_t* pdsch_cfg, - const srslte_dci_dl_nr_t* dci_dl, - srslte_sch_cfg_nr_t* cfg, - srslte_sch_grant_nr_t* pdsch_grant); +SRSLTE_API int srslte_ra_dl_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* pdsch_cfg, + const srslte_dci_dl_nr_t* dci_dl, + srslte_sch_cfg_nr_t* cfg, + srslte_sch_grant_nr_t* pdsch_grant); #endif // SRSLTE_RA_NR_H diff --git a/lib/include/srslte/phy/phch/ra_ul_nr.h b/lib/include/srslte/phy/phch/ra_ul_nr.h index 12bc5b1ff..3515d9d71 100644 --- a/lib/include/srslte/phy/phch/ra_ul_nr.h +++ b/lib/include/srslte/phy/phch/ra_ul_nr.h @@ -13,10 +13,59 @@ #ifndef SRSLTE_RA_UL_NR_H #define SRSLTE_RA_UL_NR_H +#include "dci_nr.h" #include "srslte/config.h" +#include "srslte/phy/phch/phch_cfg_nr.h" #include "srslte/phy/phch/pucch_cfg_nr.h" #include "uci_cfg_nr.h" +/** + * @brief Calculates the PUSCH time resource allocation and stores it in the provided PUSCH NR grant. + * + * @remark Defined by TS 38.214 V15.10.0 section 6.1.2.1.1 Determination of the resource allocation table to be used for + * PUSCH + * + * @param cfg Flattened PUSCH configuration provided from higher layers + * @param rnti_type Type of the RNTI of the corresponding DCI + * @param ss_type Type of the SS for PDCCH + * @param coreset_id CORESET identifier associated with the PDCCH transmission + * @param m Time domain resource assignment field value m provided in DCI + * @param[out] Provides grant pointer to fill + * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code + */ +SRSLTE_API int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_rnti_type_t rnti_type, + const srslte_search_space_type_t ss_type, + const uint32_t coreset_id, + const uint8_t m, + srslte_sch_grant_nr_t* grant); + +/** + * @brief Calculates the PUSCH time resource default A and stores it in the provided PUSCH NR grant. + * + * @remark Defined by TS 38.214 V15.10.0 Table 6.1.2.1.1-2: Default PUSCH time domain resource allocation A for normal + * CP + * + * @param scs_cfg Sub-carrier spacing configuration for PUSCH (μ) + * @param m Time domain resource assignment field value m of the DCI + * @param[out] grant PUSCH grant + * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code + */ +SRSLTE_API int +srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant); + +/** + * @brief Calculates the number of PUSCH-DMRS CDM groups without data for DCI format 0_0 + * + * @remark Defined by TS 38.214 V15.10.0 6.2.2 UE DM-RS transmission procedure + * + * @param cfg PUSCH NR configuration by upper layers + * @param[out] grant Provides grant pointer to fill + * @return Returns SRSLTE_SUCCESS if the provided data is valid, otherwise it returns SRSLTE_ERROR code + */ +SRSLTE_API int srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(const srslte_sch_cfg_nr_t* cfg, + srslte_sch_grant_nr_t* grant); + /** * @brief Calculates the minimum number of PRB required for transmitting NR-PUCCH Format 2, 3 or 4 * @remark Based in TS 38.213 9.2.5.1 UE procedure for multiplexing HARQ-ACK or CSI and SR in a PUCCH @@ -25,4 +74,19 @@ SRSLTE_API int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* resource, const srslte_uci_cfg_nr_t* uci_cfg); +/** + * @brief Calculates the PUSCH frequency resource allocation and stores it in the provided PUSCH NR grant. + * + * @remark Defined by TS 38.214 V15.10.0 section 5.1.2.2 + * @param carrier Carrier information + * @param cfg PDSCH NR configuration by upper layers + * @param dci_dl Unpacked DCI used to schedule the PDSCH grant + * @param[out] grant Provides grant pointer to fill + * @return SRSLTE_SUCCESS if the provided data is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_ra_ul_nr_freq(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_dci_ul_nr_t* dci_ul, + srslte_sch_grant_nr_t* grant); + #endif // SRSLTE_RA_UL_NR_H diff --git a/lib/include/srslte/phy/ue/ue_ul_nr.h b/lib/include/srslte/phy/ue/ue_ul_nr.h new file mode 100644 index 000000000..5827f7524 --- /dev/null +++ b/lib/include/srslte/phy/ue/ue_ul_nr.h @@ -0,0 +1,29 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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. + * + */ + +/****************************************************************************** + * @file ue_dl_nr.h + * + * Description: NR UE uplink physical layer procedures for data + * + * This module is a frontend to all the uplink data channel processing modules. + * + * Reference: + *****************************************************************************/ + +#ifndef SRSLTE_UE_UL_DATA_H +#define SRSLTE_UE_UL_DATA_H + +#include "srslte/phy/common/phy_common_nr.h" +#include "srslte/phy/phch/phch_cfg_nr.h" + +#endif // SRSLTE_UE_UL_DATA_H diff --git a/lib/include/srslte/phy/ue/ue_ul_nr_data.h b/lib/include/srslte/phy/ue/ue_ul_nr_data.h deleted file mode 100644 index 3dbcae6fd..000000000 --- a/lib/include/srslte/phy/ue/ue_ul_nr_data.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2020 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. - * - */ - -/****************************************************************************** - * @file ue_dl_nr.h - * - * Description: NR UE uplink physical layer procedures for data - * - * This module is a frontend to all the uplink data channel processing modules. - * - * Reference: - *****************************************************************************/ - -#ifndef SRSLTE_UE_UL_DATA_H -#define SRSLTE_UE_UL_DATA_H - -#include "srslte/phy/common/phy_common_nr.h" -#include "srslte/phy/phch/phch_cfg_nr.h" - -/** - * @brief Calculates the PUSCH time resource default A and stores it in the provided PUSCH NR grant. - * - * @remark Defined by TS 38.214 V15.10.0 Table 6.1.2.1.1-2: Default PUSCH time domain resource allocation A for normal - * CP - * - * @param m Time domain resource assignment field value m of the DCI - * @param[out] grant PUSCH grant - * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code - */ -SRSLTE_API int srslte_ue_ul_nr_pdsch_time_resource_default_A(uint32_t m, srslte_sch_grant_nr_t* grant); - -/** - * @brief Calculates the number of PUSCH-DMRS CDM groups without data for DCI format 0_0 - * - * @remark Defined by TS 38.214 V15.10.0 6.2.2 UE DM-RS transmission procedure - * - * @param cfg PUSCH NR configuration by upper layers - * @param[out] grant Provides grant pointer to fill - * @return Returns SRSLTE_SUCCESS if the provided data is valid, otherwise it returns SRSLTE_ERROR code - */ -SRSLTE_API int srslte_ue_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(const srslte_sch_cfg_nr_t* cfg, - srslte_sch_grant_nr_t* grant); - - -#endif // SRSLTE_UE_UL_DATA_H diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c index a64d83a97..378110ef2 100644 --- a/lib/src/phy/phch/dci_nr.c +++ b/lib/src/phy/phch/dci_nr.c @@ -14,6 +14,15 @@ #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/debug.h" +static int dci_nr_format_0_0_freq_resource_size(const srslte_carrier_nr_t* carrier) +{ + if (carrier == NULL) { + return SRSLTE_ERROR; + } + + return (int)ceil(log2(carrier->nof_prb * (carrier->nof_prb + 1) / 2.0)); +} + static int dci_nr_format_1_0_freq_resource_size(const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset0, srslte_rnti_type_t rnti_type) @@ -64,6 +73,222 @@ int srslte_dci_nr_pack(const srslte_carrier_nr_t* carrier, return SRSLTE_SUCCESS; } +int srslte_dci_nr_format_0_0_pack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset0, + const srslte_dci_ul_nr_t* dci, + srslte_dci_msg_nr_t* msg) +{ + uint32_t trim = 0; // hard-coded bit trimming + bool enable_hopping = false; // hard-coded PUSCH hopping + uint32_t padding = 0; // Hard-coded padding + bool supplementary_uplink = false; // Hard-coded supplementary Uplink + uint8_t* y = msg->payload; + srslte_rnti_type_t rnti_type = msg->rnti_type; + + if (carrier == NULL) { + return SRSLTE_ERROR; + } + + // Check RNTI type + if (rnti_type != srslte_rnti_type_c && rnti_type != srslte_rnti_type_cs && rnti_type != srslte_rnti_type_mcs_c) { + return SRSLTE_ERROR; + } + + // Identifier for DCI formats – 1 bits + *y = 0; + 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; + srslte_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 < SRSLTE_SUCCESS || N - N_UL_hop <= 0) { + return SRSLTE_ERROR; + } + srslte_bit_unpack(dci->freq_domain_assigment, &y, N - N_UL_hop - trim); + + // Time domain resource assignment – 4 bits + srslte_bit_unpack(dci->time_domain_assigment, &y, 4); + + // Frequency hopping flag – 1 bit + srslte_bit_unpack(dci->freq_hopping_flag, &y, 1); + + // Modulation and coding scheme – 5 bits + srslte_bit_unpack(dci->mcs, &y, 5); + + // New data indicator – 1 bit + srslte_bit_unpack(dci->ndi, &y, 1); + + // Redundancy version – 2 bits + srslte_bit_unpack(dci->rv, &y, 2); + + // HARQ process number – 4 bits + srslte_bit_unpack(dci->pid, &y, 4); + + // TPC command for scheduled PUSCH – 2 bits + srslte_bit_unpack(dci->tpc, &y, 2); + + // Padding goes here + for (uint32_t i = 0; i < padding; i++) { + *(y++) = 0; + } + + // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, othwerwise 0 + if (supplementary_uplink) { + *(y++) = 0; + } + + msg->nof_bits = srslte_dci_nr_format_0_0_sizeof(carrier, coreset0, rnti_type); + if (msg->nof_bits != y - msg->payload) { + ERROR("Unpacked bits readed (%d) do NOT match payload size (%d)\n", msg->nof_bits, (int)(y - msg->payload)); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_dci_nr_format_0_0_unpack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_dci_msg_nr_t* msg, + srslte_dci_ul_nr_t* dci) +{ + uint32_t trim = 0; // hard-coded bit trimming + bool enable_hopping = false; // hard-coded PUSCH hopping + uint32_t padding = 0; // Hard-coded padding + bool supplementary_uplink = false; // Hard-coded supplementary Uplink + uint8_t* y = msg->payload; + srslte_rnti_type_t rnti_type = msg->rnti_type; + + if (carrier == NULL) { + return SRSLTE_ERROR; + } + + // Check RNTI type + if (rnti_type != srslte_rnti_type_c && rnti_type != srslte_rnti_type_cs && rnti_type != srslte_rnti_type_mcs_c) { + return SRSLTE_ERROR; + } + + if (msg->nof_bits != srslte_dci_nr_format_0_0_sizeof(carrier, coreset, rnti_type)) { + ERROR("Invalid number of bits %d, expected %d\n", + msg->nof_bits, + srslte_dci_nr_format_0_0_sizeof(carrier, coreset, rnti_type)); + return SRSLTE_ERROR; + } + + // Identifier for DCI formats – 1 bits + if (*(y++) != 0) { + ERROR("Wrond DCI format\n"); + return SRSLTE_ERROR; + } + + // 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; + dci->frequency_offset = srslte_bit_pack(&y, N_UL_hop); + + // Frequency domain resource assignment + int N = dci_nr_format_0_0_freq_resource_size(carrier); + if (N < SRSLTE_SUCCESS || N - N_UL_hop <= 0) { + return SRSLTE_ERROR; + } + dci->freq_domain_assigment = srslte_bit_pack(&y, N - N_UL_hop - trim); + + // Time domain resource assignment – 4 bits + dci->time_domain_assigment = srslte_bit_pack(&y, 4); + + // Frequency hopping flag – 1 bit + dci->freq_hopping_flag = srslte_bit_pack(&y, 1); + + // Modulation and coding scheme – 5 bits + dci->mcs = srslte_bit_pack(&y, 5); + + // New data indicator – 1 bit + dci->ndi = srslte_bit_pack(&y, 1); + + // Redundancy version – 2 bits + dci->rv = srslte_bit_pack(&y, 2); + + // HARQ process number – 4 bits + dci->pid = srslte_bit_pack(&y, 4); + + // TPC command for scheduled PUSCH – 2 bits + dci->tpc = srslte_bit_pack(&y, 2); + + // Padding goes here + for (uint32_t i = 0; i < padding; i++) { + y++; + } + + // UL/SUL indicator – 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, othwerwise 0 + if (supplementary_uplink) { + y++; + } + + return SRSLTE_SUCCESS; +} + +int srslte_dci_nr_format_0_0_sizeof(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_rnti_type_t rnti_type) +{ + uint32_t trim = 0; // hard-coded bit trimming + bool enable_hopping = false; // hard-coded PUSCH hopping + uint32_t padding = 0; // 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 < SRSLTE_SUCCESS || N - N_UL_hop <= 0) { + return SRSLTE_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, othwerwise 0 + if (supplementary_uplink) { + count++; + } + + return count; +} + +static int dci_nr_format_0_0_to_str(const srslte_dci_ul_nr_t* dci, char* str, uint32_t str_len) +{ + return SRSLTE_ERROR; +} + int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset, const srslte_dci_dl_nr_t* dci, @@ -198,11 +423,10 @@ int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrier, // Identifier for DCI formats – 1 bits if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { // The value of this bit field is always set to 1, indicating a DL DCI format - if (*y != 1) { + if (*(y++) != 1) { ERROR("Wrond DCI format\n"); return SRSLTE_ERROR; } - y++; } if (rnti_type == srslte_rnti_type_p) { @@ -298,7 +522,7 @@ int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset, srslte_rnti_type_t rnti_type) { - uint32_t count = 0; + int count = 0; // Identifier for DCI formats – 1 bits if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { @@ -467,7 +691,19 @@ static int dci_nr_format_1_0_to_str(const srslte_dci_dl_nr_t* dci, char* str, ui return len; } -int srslte_dci_nr_to_str(const srslte_dci_dl_nr_t* dci, char* str, uint32_t str_len) +int srslte_dci_ul_nr_to_str(const srslte_dci_ul_nr_t* dci, char* str, uint32_t str_len) +{ + // Pack DCI + switch (dci->format) { + case srslte_dci_format_nr_0_0: + return dci_nr_format_0_0_to_str(dci, str, str_len); + default:; // Do nothing + } + + return srslte_print_check(str, str_len, 0, "unknown"); +} + +int srslte_dci_dl_nr_to_str(const srslte_dci_dl_nr_t* dci, char* str, uint32_t str_len) { // Pack DCI switch (dci->format) { diff --git a/lib/src/phy/phch/ra_dl_nr.c b/lib/src/phy/phch/ra_dl_nr.c index de0d2b8ac..cdb2ce877 100644 --- a/lib/src/phy/phch/ra_dl_nr.c +++ b/lib/src/phy/phch/ra_dl_nr.c @@ -10,21 +10,9 @@ * */ #include "srslte/phy/phch/ra_dl_nr.h" +#include "ra_helper.h" #include "srslte/phy/utils/debug.h" -static void compute_s_and_l(uint32_t N, uint32_t v, uint32_t* S, uint32_t* L) -{ - uint32_t low = v % N; - uint32_t high = v / N; - if (high + 1 + low <= N) { - *S = low; - *L = high + 1; - } else { - *S = N - 1 - low; - *L = N - high + 1; - } -} - // Validate S and L combination for TypeA time domain resource allocation static bool check_time_ra_typeA(uint32_t* S, uint32_t* L) { @@ -108,7 +96,6 @@ int srslte_ra_dl_nr_time_default_A(uint32_t m, srslte_dmrs_sch_typeA_pos_t dmrs_ // Select start symbol (S) and length (L) switch (dmrs_typeA_pos) { - case srslte_dmrs_sch_typeA_pos_2: grant->S = S_pos2[m]; grant->L = L_pos2[m]; @@ -125,23 +112,22 @@ int srslte_ra_dl_nr_time_default_A(uint32_t m, srslte_dmrs_sch_typeA_pos_t dmrs_ return SRSLTE_SUCCESS; } -void srslte_ra_dl_nr_time_hl(const srslte_pdsch_time_ra_t* hl_ra_cfg, srslte_sch_grant_nr_t* grant) +static void ra_dl_nr_time_hl(const srslte_sch_time_ra_t* hl_ra_cfg, srslte_sch_grant_nr_t* grant) { // Compute S and L from SLIV from higher layers - compute_s_and_l(SRSLTE_NSYMB_PER_SLOT_NR, hl_ra_cfg->sliv, &grant->S, &grant->L); + ra_helper_compute_s_and_l(SRSLTE_NSYMB_PER_SLOT_NR, hl_ra_cfg->sliv, &grant->S, &grant->L); - grant->k0 = hl_ra_cfg->k0; + grant->k0 = hl_ra_cfg->k; grant->mapping = hl_ra_cfg->mapping_type; } -int srslte_ra_dl_nr_time(const srslte_pdsch_cfg_nr_t* cfg, +int srslte_ra_dl_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, const srslte_rnti_type_t rnti_type, const srslte_search_space_type_t ss_type, const uint32_t coreset_id, const uint8_t m, srslte_sch_grant_nr_t* grant) { - if (cfg == NULL || grant == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -161,8 +147,8 @@ int srslte_ra_dl_nr_time(const srslte_pdsch_cfg_nr_t* cfg, } else if ((rnti_type == srslte_rnti_type_ra || rnti_type == srslte_rnti_type_tc) && ss_type == srslte_search_space_type_common_1) { // Row 3 - if (cfg->nof_common_pdsch_time_ra > 0) { - srslte_ra_dl_nr_time_hl(&cfg->common_pdsch_time_ra[m], grant); + if (cfg->nof_common_time_ra > 0) { + ra_dl_nr_time_hl(&cfg->common_time_ra[m], grant); } else { // Note: Only Default A is supported, which corresponds SS/PBCH block and coreset mux pattern 1 srslte_ra_dl_nr_time_default_A(m, cfg->typeA_pos, grant); @@ -174,8 +160,8 @@ int srslte_ra_dl_nr_time(const srslte_pdsch_cfg_nr_t* cfg, rnti_type == srslte_rnti_type_cs) && SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id == 0) { // Row 5 - if (cfg->nof_common_pdsch_time_ra > 0) { - srslte_ra_dl_nr_time_hl(&cfg->common_pdsch_time_ra[m], grant); + if (cfg->nof_common_time_ra > 0) { + ra_dl_nr_time_hl(&cfg->common_time_ra[m], grant); } else { srslte_ra_dl_nr_time_default_A(m, cfg->typeA_pos, grant); } @@ -183,10 +169,10 @@ int srslte_ra_dl_nr_time(const srslte_pdsch_cfg_nr_t* cfg, rnti_type == srslte_rnti_type_cs) && ((SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id != 0) || ss_type == srslte_search_space_type_ue)) { // Row 6 - if (cfg->nof_pdsch_time_ra > 0) { - srslte_ra_dl_nr_time_hl(&cfg->pdsch_time_ra[m], grant); - } else if (cfg->nof_common_pdsch_time_ra > 0) { - srslte_ra_dl_nr_time_hl(&cfg->common_pdsch_time_ra[m], grant); + if (cfg->nof_dedicated_time_ra > 0) { + ra_dl_nr_time_hl(&cfg->dedicated_time_ra[m], grant); + } else if (cfg->nof_common_time_ra > 0) { + ra_dl_nr_time_hl(&cfg->common_time_ra[m], grant); } else { srslte_ra_dl_nr_time_default_A(m, cfg->typeA_pos, grant); } @@ -239,10 +225,10 @@ uint32_t srslte_ra_dl_nr_type0_P(uint32_t bwp_size, bool config_is_1) } } -static int ra_freq_type0(const srslte_carrier_nr_t* carrier, - const srslte_pdsch_cfg_nr_t* cfg, - const srslte_dci_dl_nr_t* dci_dl, - srslte_sch_grant_nr_t* grant) +static int ra_freq_type0(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_dci_dl_nr_t* dci_dl, + srslte_sch_grant_nr_t* grant) { uint32_t P = srslte_ra_dl_nr_type0_P(carrier->nof_prb, cfg->rbg_size_cfg_1); @@ -268,44 +254,11 @@ static int ra_freq_type0(const srslte_carrier_nr_t* carrier, return 0; } -static int -ra_freq_type1(const srslte_carrier_nr_t* carrier, const srslte_dci_dl_nr_t* dci_dl, srslte_sch_grant_nr_t* grant) +int srslte_ra_dl_nr_freq(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_dci_dl_nr_t* dci_dl, + srslte_sch_grant_nr_t* grant) { - - uint32_t riv = dci_dl->freq_domain_assigment; - uint32_t N_bwp_size = carrier->nof_prb; - - uint32_t start = 0; - uint32_t len = 0; - compute_s_and_l(N_bwp_size, riv, &start, &len); - - if (start + len > N_bwp_size) { - ERROR("RIV 0x%x for BWP size %d resulted in freq=%d:%d\n", riv, N_bwp_size, start, len); - return SRSLTE_ERROR; - } - - for (uint32_t i = 0; i < start; i++) { - grant->prb_idx[i] = false; - } - - for (uint32_t i = start; i < start + len; i++) { - grant->prb_idx[i] = true; - } - - for (uint32_t i = start + len; i < SRSLTE_MAX_PRB_NR; i++) { - grant->prb_idx[i] = false; - } - grant->nof_prb = len; - - return SRSLTE_SUCCESS; -} - -int srslte_ra_dl_nr_freq(const srslte_carrier_nr_t* carrier, - const srslte_pdsch_cfg_nr_t* cfg, - const srslte_dci_dl_nr_t* dci_dl, - srslte_sch_grant_nr_t* grant) -{ - if (cfg == NULL || grant == NULL || dci_dl == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -313,7 +266,7 @@ int srslte_ra_dl_nr_freq(const srslte_carrier_nr_t* carrier, // RA scheme if (dci_dl->format == srslte_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_freq_type1(carrier, dci_dl, grant); + return ra_helper_freq_type1(carrier->nof_prb, dci_dl->freq_domain_assigment, grant); } ra_freq_type0(carrier, cfg, dci_dl, grant); diff --git a/lib/src/phy/phch/ra_helper.h b/lib/src/phy/phch/ra_helper.h new file mode 100644 index 000000000..83f09cf3c --- /dev/null +++ b/lib/src/phy/phch/ra_helper.h @@ -0,0 +1,59 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_RA_HELPER_H +#define SRSLTE_RA_HELPER_H + +#include "srslte/phy/utils/debug.h" +#include + +static inline void ra_helper_compute_s_and_l(uint32_t N, uint32_t v, uint32_t* S, uint32_t* L) +{ + uint32_t low = v % N; + uint32_t high = v / N; + if (high + 1 + low <= N) { + *S = low; + *L = high + 1; + } else { + *S = N - 1 - low; + *L = N - high + 1; + } +} + +static int ra_helper_freq_type1(uint32_t N_bwp_size, uint32_t riv, srslte_sch_grant_nr_t* grant) +{ + uint32_t start = 0; + uint32_t len = 0; + ra_helper_compute_s_and_l(N_bwp_size, riv, &start, &len); + + if (start + len > N_bwp_size) { + ERROR("RIV 0x%x for BWP size %d resulted in freq=%d:%d\n", riv, N_bwp_size, start, len); + return SRSLTE_ERROR; + } + + for (uint32_t i = 0; i < start; i++) { + grant->prb_idx[i] = false; + } + + for (uint32_t i = start; i < start + len; i++) { + grant->prb_idx[i] = true; + } + + for (uint32_t i = start + len; i < SRSLTE_MAX_PRB_NR; i++) { + grant->prb_idx[i] = false; + } + grant->nof_prb = len; + + return SRSLTE_SUCCESS; +} + +#endif // SRSLTE_RA_HELPER_H diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 7be424e03..3efc5bdb8 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -13,6 +13,7 @@ #include "srslte/phy/phch/ra_nr.h" #include "srslte/phy/phch/pdsch_nr.h" #include "srslte/phy/phch/ra_dl_nr.h" +#include "srslte/phy/phch/ra_ul_nr.h" #include "srslte/phy/utils/debug.h" typedef struct { @@ -215,7 +216,6 @@ static ra_nr_table_t ra_nr_select_table(srslte_mcs_table_t mcs_table, srslte_search_space_type_t search_space_type, srslte_rnti_type_t rnti_type) { - // Check if it is a PUSCH transmission if (dci_format == srslte_dci_format_nr_0_0 || dci_format == srslte_dci_format_nr_0_1 || dci_format == srslte_dci_format_nr_rar || dci_format == srslte_dci_format_nr_cg) { @@ -455,16 +455,15 @@ int srslte_ra_nr_fill_tb(const srslte_sch_cfg_nr_t* pdsch_cfg, return SRSLTE_SUCCESS; } -static int ra_dl_dmrs(const srslte_pdsch_cfg_nr_t* pdsch_hl_cfg, - srslte_sch_grant_nr_t* pdsch_grant, - srslte_dmrs_sch_cfg_t* dmrs_cfg) +static int ra_dl_dmrs(const srslte_sch_hl_cfg_nr_t* pdsch_hl_cfg, + srslte_sch_grant_nr_t* pdsch_grant, + srslte_dmrs_sch_cfg_t* dmrs_cfg) { const bool dedicated_dmrs_present = (pdsch_grant->mapping == srslte_sch_mapping_type_A) - ? pdsch_hl_cfg->dmrs_typeA_present - : pdsch_hl_cfg->dmrs_typeB_present; + ? pdsch_hl_cfg->dmrs_typeA.present + : pdsch_hl_cfg->dmrs_typeB.present; if (pdsch_grant->dci_format == srslte_dci_format_nr_1_0 || !dedicated_dmrs_present) { - if (pdsch_grant->mapping == srslte_sch_mapping_type_A) { // Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig dmrs_cfg->additional_pos = srslte_dmrs_sch_add_pos_2; @@ -490,11 +489,11 @@ static int ra_dl_dmrs(const srslte_pdsch_cfg_nr_t* pdsch_hl_cfg, return SRSLTE_ERROR; } -int srslte_ra_dl_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, - const srslte_pdsch_cfg_nr_t* pdsch_hl_cfg, - const srslte_dci_dl_nr_t* dci_dl, - srslte_sch_cfg_nr_t* pdsch_cfg, - srslte_sch_grant_nr_t* pdsch_grant) +int srslte_ra_dl_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* pdsch_hl_cfg, + const srslte_dci_dl_nr_t* dci_dl, + srslte_sch_cfg_nr_t* pdsch_cfg, + srslte_sch_grant_nr_t* pdsch_grant) { // 5.2.1.1 Resource allocation in time domain if (srslte_ra_dl_nr_time(pdsch_hl_cfg, @@ -535,3 +534,49 @@ int srslte_ra_dl_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, return SRSLTE_SUCCESS; } + +int srslte_ra_ul_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* pusch_hl_cfg, + const srslte_dci_ul_nr_t* dci_ul, + srslte_sch_cfg_nr_t* pusch_cfg, + srslte_sch_grant_nr_t* pusch_grant) +{ + // 5.2.1.1 Resource allocation in time domain + if (srslte_ra_dl_nr_time(pusch_hl_cfg, + dci_ul->rnti_type, + dci_ul->search_space, + dci_ul->coreset_id, + dci_ul->time_domain_assigment, + pusch_grant) < SRSLTE_SUCCESS) { + ERROR("Error computing time domain resource allocation\n"); + return SRSLTE_ERROR; + } + + // 5.1.2.2 Resource allocation in frequency domain + if (srslte_ra_ul_nr_freq(carrier, pusch_hl_cfg, dci_ul, pusch_grant) < SRSLTE_SUCCESS) { + ERROR("Error computing frequency domain resource allocation\n"); + return SRSLTE_ERROR; + } + + // 5.1.2.3 Physical resource block (PRB) bundling + // ... + + 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; + + // 5.1.6.2 DM-RS reception procedure + if (ra_dl_dmrs(pusch_hl_cfg, pusch_grant, &pusch_cfg->dmrs) < SRSLTE_SUCCESS) { + ERROR("Error selecting DMRS configuration"); + return SRSLTE_ERROR; + } + + // 5.1.3 Modulation order, target code rate, redundancy version and transport block size determination + if (srslte_ra_nr_fill_tb(pusch_cfg, pusch_grant, dci_ul->mcs, &pusch_grant->tb[0]) < SRSLTE_SUCCESS) { + ERROR("Error filing tb\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 17dbe2fe4..06c2e78b2 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -11,10 +11,211 @@ */ #include "srslte/phy/phch/ra_ul_nr.h" +#include "ra_helper.h" #include "srslte/phy/ch_estimation/dmrs_pucch.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/utils/debug.h" +typedef struct { + srslte_sch_mapping_type_t mapping; + uint32_t K2; + uint32_t S; + uint32_t L; +} ue_ra_time_resource_t; + +static const ue_ra_time_resource_t ue_ul_default_A_lut[16] = {{srslte_sch_mapping_type_A, 0, 0, 14}, + {srslte_sch_mapping_type_A, 0, 0, 12}, + {srslte_sch_mapping_type_A, 0, 0, 10}, + {srslte_sch_mapping_type_B, 0, 2, 10}, + {srslte_sch_mapping_type_B, 0, 4, 10}, + {srslte_sch_mapping_type_B, 0, 4, 8}, + {srslte_sch_mapping_type_B, 0, 4, 6}, + {srslte_sch_mapping_type_A, 1, 0, 14}, + {srslte_sch_mapping_type_A, 1, 0, 12}, + {srslte_sch_mapping_type_A, 1, 0, 10}, + {srslte_sch_mapping_type_A, 2, 0, 14}, + {srslte_sch_mapping_type_A, 2, 0, 12}, + {srslte_sch_mapping_type_A, 2, 0, 10}, + {srslte_sch_mapping_type_B, 0, 8, 6}, + {srslte_sch_mapping_type_A, 3, 0, 14}, + {srslte_sch_mapping_type_A, 3, 0, 10}}; + +int srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant) +{ + uint32_t j[4] = {1, 1, 2, 3}; + + if (grant == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (scs_cfg > 4) { + ERROR("Invalid numerology (%d)", scs_cfg); + return SRSLTE_ERROR; + } + + if (m >= 16) { + ERROR("m (%d) is out-of-range", m); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Select mapping + grant->mapping = ue_ul_default_A_lut[m].mapping; + grant->k2 = ue_ul_default_A_lut[m].K2 + j[scs_cfg]; + grant->S = ue_ul_default_A_lut[m].S; + grant->L = ue_ul_default_A_lut[m].L; + + return SRSLTE_SUCCESS; +} + +static void ra_ul_nr_time_hl(const srslte_sch_time_ra_t* hl_ra_cfg, srslte_sch_grant_nr_t* grant) +{ + // Compute S and L from SLIV from higher layers + ra_helper_compute_s_and_l(SRSLTE_NSYMB_PER_SLOT_NR, hl_ra_cfg->sliv, &grant->S, &grant->L); + + grant->k2 = hl_ra_cfg->k; + grant->mapping = hl_ra_cfg->mapping_type; +} + +// Validate S and L combination for TypeA time domain resource allocation +static bool check_time_ra_typeA(uint32_t* S, uint32_t* L) +{ + // Check values using Table 5.1.2.1-1 + if (*S != 0) { + ERROR("S (%d) is out-of-range {0}", *S); + return false; + } + + if (*L < 4 || *L > 14) { + ERROR("L (%d) is out-of-range {4,...,14}", *L); + return false; + } + + uint32_t sum = *S + *L; + if (sum < 4) { + ERROR("The sum of S (%d) and L (%d) is lower than 4", *S, *L); + return false; + } + + if (sum > 14) { + ERROR("The sum of S (%d) and L (%d) is greater than 14", *S, *L); + return false; + } + + return true; +} + +static bool check_time_ra_typeB(uint32_t* S, uint32_t* L) +{ + ERROR("Not implemented"); + return false; +} + +bool srslte_ra_ul_nr_time_validate(srslte_sch_grant_nr_t* grant) +{ + if (grant->mapping == srslte_sch_mapping_type_A) { + return check_time_ra_typeA(&grant->S, &grant->L); + } + + return check_time_ra_typeB(&grant->S, &grant->L); +} + +int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_rnti_type_t rnti_type, + const srslte_search_space_type_t ss_type, + const uint32_t coreset_id, + const uint8_t m, + srslte_sch_grant_nr_t* grant) +{ + if (cfg == NULL || grant == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (m >= SRSLTE_MAX_NOF_DL_ALLOCATION) { + ERROR("m (%d) is out-of-range", m); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Determine which PUSCH Time domain RA configuration to apply (TS 38.214 Table 6.1.2.1.1-1:) + if (ss_type == srslte_search_space_rar) { + // Row 1 + if (cfg->nof_common_time_ra == 0) { + srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION) { + ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); + } + } else if ((rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_mcs_c || + rnti_type == srslte_rnti_type_tc || rnti_type == srslte_rnti_type_cs) && + SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id == 0) { + // Row 2 + if (cfg->nof_common_time_ra == 0) { + srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION) { + ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); + } + } else if ((rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_mcs_c || + rnti_type == srslte_rnti_type_tc || rnti_type == srslte_rnti_type_cs || + rnti_type == srslte_rnti_type_sp_csi) && + ((SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id != 0) || ss_type == srslte_search_space_type_ue)) { + // Row 3 + if (cfg->nof_dedicated_time_ra > 0) { + ra_ul_nr_time_hl(&cfg->dedicated_time_ra[m], grant); + } else if (cfg->nof_common_time_ra > 0) { + ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); + } else { + srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); + } + } else { + ERROR("Unhandled case"); + } + + // Table 6.1.2.1.1-5 defines the additional subcarrier spacing specific slot delay value for the first transmission of + // PUSCH scheduled by the RAR. When the UE transmits a PUSCH scheduled by RAR, the Δ value specific to the PUSCH + // subcarrier spacing μ PUSCH is applied in addition to the K 2 value. + if (ss_type == srslte_search_space_rar) { + uint32_t delta[4] = {2, 3, 4, 6}; + if (cfg->scs_cfg <= 4) { + ERROR("Invalid numerology"); + return SRSLTE_ERROR; + } + grant->k2 += delta[cfg->scs_cfg]; + } + + // Validate S and L parameters + if (!srslte_ra_ul_nr_time_validate(grant)) { + ERROR("Invalid Time RA S=%d; L=%d; m=%d", grant->S, grant->L, m); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(const srslte_sch_cfg_nr_t* cfg, + srslte_sch_grant_nr_t* grant) +{ + if (cfg == NULL || grant == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + /* According to TS 38.214 V15.10.0 6.2.2 UE DM-RS transmission procedure: + * For PUSCH scheduled by DCI format 0_0 or by activation DCI format 0_0 with CRC scrambled by CS-RNTI, the UE + * shall assume the number of DM-RS CDM groups without data is 1 which corresponds to CDM group 0 for the case of + * PUSCH with allocation duration of 2 or less OFDM symbols with transform precoding disabled, the UE shall assume + * that the number of DM-RS CDM groups without data is 3 which corresponds to CDM group {0,1,2} for the case of PUSCH + * scheduled by activation DCI format 0_0 and the dmrs-Type in cg-DMRS-Configuration equal to 'type2' and the PUSCH + * allocation duration being more than 2 OFDM symbols, and the UE shall assume that the number of DM-RS CDM groups + * without data is 2 which corresponds to CDM group {0,1} for all other cases. + */ + if (grant->L <= 2 && !cfg->enable_transform_precoder) { + grant->nof_dmrs_cdm_groups_without_data = 1; + // } else if (grant->L > 2 && cfg->dmrs_cg.type == srslte_dmrs_sch_type_2){ + // grant->nof_dmrs_cdm_groups_without_data = 3; + } else { + grant->nof_dmrs_cdm_groups_without_data = 2; + } + + return SRSLTE_SUCCESS; +} + #define RA_UL_PUCCH_CODE_RATE_N 8 #define RA_UL_PUCCH_CODE_RATE_RESERVED NAN @@ -25,7 +226,7 @@ static const double ra_ul_pucch_code_rate_table[RA_UL_PUCCH_CODE_RATE_N] = static double ra_ul_nr_pucch_code_rate_r(const srslte_pucch_nr_resource_t* resource) { if (resource->max_code_rate >= RA_UL_PUCCH_CODE_RATE_RESERVED) { - ERROR("Invalid code rate\n"); + ERROR("Invalid code rate"); return RA_UL_PUCCH_CODE_RATE_RESERVED; } @@ -42,7 +243,7 @@ static double ra_ul_nr_pucch_code_rate_r(const srslte_pucch_nr_resource_t* resou // case SRSLTE_PUCCH_NR_FORMAT_4: // return SRSLTE_PUCCH_NR_FORMAT4_NPRB; // default: -// ERROR("Invalid case\n"); +// ERROR("Invalid case"); // break; // } // return SRSLTE_ERROR; @@ -59,7 +260,7 @@ static int ra_ul_nr_pucch_nre(const srslte_pucch_nr_resource_t* resource) case SRSLTE_PUCCH_NR_FORMAT_4: return SRSLTE_NRE / resource->occ_lenth; default: - ERROR("Invalid case\n"); + ERROR("Invalid case"); break; } return SRSLTE_ERROR; @@ -84,7 +285,7 @@ static int ra_ul_nr_pucch_nsymb(const srslte_pucch_nr_resource_t* resource) return (int)resource->nof_symbols - nsymb_dmrs; } default: - ERROR("Invalid case\n"); + ERROR("Invalid case"); break; } return SRSLTE_ERROR; @@ -100,7 +301,7 @@ static int ra_ul_nr_pucch_qm(const srslte_pucch_nr_resource_t* resource) case SRSLTE_PUCCH_NR_FORMAT_4: return resource->enable_pi_bpsk ? 1 : 2; default: - ERROR("Invalid case\n"); + ERROR("Invalid case"); break; } return SRSLTE_ERROR; @@ -116,28 +317,28 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r // Get maximum allowed code rate double r = ra_ul_nr_pucch_code_rate_r(resource); if (!isnormal(r)) { - ERROR("Invalid coderate %f\n", r); + ERROR("Invalid coderate %f", r); return SRSLTE_ERROR; } // Get number of RE/PRB int nre = ra_ul_nr_pucch_nre(resource); if (nre < SRSLTE_SUCCESS) { - ERROR("Getting nre\n"); + ERROR("Getting nre"); return SRSLTE_ERROR; } // Get number of symbols int nsymb = ra_ul_nr_pucch_nsymb(resource); if (nsymb < SRSLTE_SUCCESS) { - ERROR("Getting nsymb\n"); + ERROR("Getting nsymb"); return SRSLTE_ERROR; } // Get modulation order int qm = ra_ul_nr_pucch_qm(resource); if (qm < SRSLTE_SUCCESS) { - ERROR("Getting qm\n"); + ERROR("Getting qm"); return SRSLTE_ERROR; } @@ -155,4 +356,23 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r // Return the minimum return (int)ceil(O_total / nof_bits_rb); -} \ No newline at end of file +} + +int srslte_ra_ul_nr_freq(const srslte_carrier_nr_t* carrier, + const srslte_sch_hl_cfg_nr_t* cfg, + const srslte_dci_ul_nr_t* dci_ul, + srslte_sch_grant_nr_t* grant) +{ + if (cfg == NULL || grant == NULL || dci_ul == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // RA scheme + if (dci_ul->format == srslte_dci_format_nr_0_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_ul->freq_domain_assigment, grant); + } + + ERROR("Only DCI Format 0_0 is supported"); + return SRSLTE_ERROR; +} diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index 097dc1f87..c0c8c7a68 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -12,7 +12,7 @@ #include "srslte/phy/phch/pusch_nr.h" #include "srslte/phy/phch/ra_nr.h" -#include "srslte/phy/ue/ue_ul_nr_data.h" +#include "srslte/phy/phch/ra_ul_nr.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/random.h" #include "srslte/phy/utils/vector.h" @@ -152,13 +152,13 @@ int main(int argc, char** argv) } // Use grant default A time resources with m=0 - if (srslte_ue_ul_nr_pdsch_time_resource_default_A(0, &pusch_grant) < SRSLTE_SUCCESS) { + if (srslte_ra_ul_nr_pdsch_time_resource_default_A(carrier.numerology, 0, &pusch_grant) < SRSLTE_SUCCESS) { ERROR("Error loading default grant\n"); goto clean_exit; } // Load number of DMRS CDM groups without data - if (srslte_ue_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_grant) < SRSLTE_SUCCESS) { + if (srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_grant) < SRSLTE_SUCCESS) { ERROR("Error loading number of DMRS CDM groups without data\n"); goto clean_exit; } @@ -188,7 +188,6 @@ int main(int argc, char** argv) for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { for (mcs = mcs_start; mcs < mcs_end; mcs++) { - for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { pusch_grant.prb_idx[n] = (n < n_prb); } diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c new file mode 100644 index 000000000..bfc082d59 --- /dev/null +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -0,0 +1,13 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/phy/ue/ue_ul_nr.h" +#include "srslte/phy/utils/debug.h" diff --git a/lib/src/phy/ue/ue_ul_nr_data.c b/lib/src/phy/ue/ue_ul_nr_data.c deleted file mode 100644 index eecb3394d..000000000 --- a/lib/src/phy/ue/ue_ul_nr_data.c +++ /dev/null @@ -1,84 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2020 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 "srslte/phy/ue/ue_ul_nr_data.h" -#include "srslte/phy/utils/debug.h" - -typedef struct { - srslte_sch_mapping_type_t mapping; - uint32_t K2; - uint32_t S; - uint32_t L; -} ue_ul_time_resource_t; - -static const ue_ul_time_resource_t ue_ul_default_A_lut[16] = {{srslte_sch_mapping_type_A, 0, 0, 14}, - {srslte_sch_mapping_type_A, 0, 0, 12}, - {srslte_sch_mapping_type_A, 0, 0, 10}, - {srslte_sch_mapping_type_B, 0, 2, 10}, - {srslte_sch_mapping_type_B, 0, 4, 10}, - {srslte_sch_mapping_type_B, 0, 4, 8}, - {srslte_sch_mapping_type_B, 0, 4, 6}, - {srslte_sch_mapping_type_A, 1, 0, 14}, - {srslte_sch_mapping_type_A, 1, 0, 12}, - {srslte_sch_mapping_type_A, 1, 0, 10}, - {srslte_sch_mapping_type_A, 2, 0, 14}, - {srslte_sch_mapping_type_A, 2, 0, 12}, - {srslte_sch_mapping_type_A, 2, 0, 10}, - {srslte_sch_mapping_type_B, 0, 8, 6}, - {srslte_sch_mapping_type_A, 3, 0, 14}, - {srslte_sch_mapping_type_A, 3, 0, 10}}; - -int srslte_ue_ul_nr_pdsch_time_resource_default_A(uint32_t m, srslte_sch_grant_nr_t* grant) -{ - if (grant == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (m >= 16) { - ERROR("m (%d) is out-of-range\n", m); - return SRSLTE_ERROR_INVALID_INPUTS; - } - - // Select mapping - grant->mapping = ue_ul_default_A_lut[m].mapping; - grant->k2 = ue_ul_default_A_lut[m].K2; - grant->S = ue_ul_default_A_lut[m].S; - grant->L = ue_ul_default_A_lut[m].L; - - return SRSLTE_SUCCESS; -} - -int srslte_ue_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(const srslte_sch_cfg_nr_t* cfg, - srslte_sch_grant_nr_t* grant) -{ - if (cfg == NULL || grant == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - /* According to TS 38.214 V15.10.0 6.2.2 UE DM-RS transmission procedure: - * For PUSCH scheduled by DCI format 0_0 or by activation DCI format 0_0 with CRC scrambled by CS-RNTI, the UE - * shall assume the number of DM-RS CDM groups without data is 1 which corresponds to CDM group 0 for the case of - * PUSCH with allocation duration of 2 or less OFDM symbols with transform precoding disabled, the UE shall assume - * that the number of DM-RS CDM groups without data is 3 which corresponds to CDM group {0,1,2} for the case of PUSCH - * scheduled by activation DCI format 0_0 and the dmrs-Type in cg-DMRS-Configuration equal to 'type2' and the PUSCH - * allocation duration being more than 2 OFDM symbols, and the UE shall assume that the number of DM-RS CDM groups - * without data is 2 which corresponds to CDM group {0,1} for all other cases. - */ - if (grant->L <= 2 && !cfg->enable_transform_precoder) { - grant->nof_dmrs_cdm_groups_without_data = 1; - // } else if (grant->L > 2 && cfg->dmrs_cg.type == srslte_dmrs_sch_type_2){ - // grant->nof_dmrs_cdm_groups_without_data = 3; - } else { - grant->nof_dmrs_cdm_groups_without_data = 2; - } - - return SRSLTE_SUCCESS; -} \ No newline at end of file diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h index 58413cbbd..ca829a10b 100644 --- a/srsenb/hdr/phy/nr/cc_worker.h +++ b/srsenb/hdr/phy/nr/cc_worker.h @@ -29,7 +29,7 @@ typedef struct { } phy_nr_args_t; typedef struct { - srslte_pdsch_cfg_nr_t pdsch; + srslte_sch_hl_cfg_nr_t pdsch; } phy_nr_cfg_t; class phy_nr_state diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc index d8980c9cd..92268bde1 100644 --- a/srsenb/src/phy/nr/cc_worker.cc +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -121,7 +121,7 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui for (uint32_t i = 0; i < nof_grants; i++) { // Get PHY config for UE // ... - srslte_pdsch_cfg_nr_t pdsch_hl_cfg = {}; + srslte_sch_hl_cfg_nr_t pdsch_hl_cfg = {}; srslte_sch_cfg_nr_t pdsch_cfg = {}; // Compute DL grant diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 6b54248c2..c54159fef 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -29,7 +29,7 @@ typedef struct { } phy_nr_args_t; typedef struct { - srslte_pdsch_cfg_nr_t pdsch; + srslte_sch_hl_cfg_nr_t pdsch; srslte_prach_cfg_t prach; srslte_ue_dl_nr_cfg_t pdcch; } phy_nr_cfg_t; @@ -128,11 +128,11 @@ public: // PDSCH-TimeDomainResourceAllocation // mappingType: typeA (0) // startSymbolAndLength: 57 - cfg.pdsch.common_pdsch_time_ra[0].mapping_type = srslte_sch_mapping_type_A; - cfg.pdsch.common_pdsch_time_ra[0].sliv = 40; - cfg.pdsch.common_pdsch_time_ra[1].mapping_type = srslte_sch_mapping_type_A; - cfg.pdsch.common_pdsch_time_ra[1].sliv = 57; - cfg.pdsch.nof_common_pdsch_time_ra = 2; + cfg.pdsch.common_time_ra[0].mapping_type = srslte_sch_mapping_type_A; + cfg.pdsch.common_time_ra[0].sliv = 40; + cfg.pdsch.common_time_ra[1].mapping_type = srslte_sch_mapping_type_A; + cfg.pdsch.common_time_ra[1].sliv = 57; + cfg.pdsch.nof_common_time_ra = 2; } }; } // namespace nr diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 0886f5e13..3ae836ed1 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -96,7 +96,7 @@ uint32_t cc_worker::get_buffer_len() bool cc_worker::work_dl() { - srslte_pdsch_cfg_nr_t pdsch_hl_cfg = phy->cfg.pdsch; + srslte_sch_hl_cfg_nr_t pdsch_hl_cfg = phy->cfg.pdsch; // Run FFT srslte_ue_dl_nr_estimate_fft(&ue_dl, &dl_slot_cfg); @@ -144,7 +144,7 @@ bool cc_worker::work_dl() // Log found DCI if (logger.info.enabled()) { std::array str; - srslte_dci_nr_to_str(dci_dl, str.data(), str.size()); + srslte_dci_dl_nr_to_str(dci_dl, str.data(), str.size()); logger.info("PDCCH: cc=%d, %s", cc_idx, str.data()); }