diff --git a/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h b/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h index b6689069c..7bd6c7f52 100644 --- a/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h +++ b/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h @@ -17,6 +17,18 @@ #include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/phch/pucch_nr.h" +#define SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB 4 + +/** + * @brief Computes the symbol indexes carrying DMRS for NR-PUCCH formats 3 and 4 + * @remark Implements TS 38.211 Table 6.4.1.3.3.2-1: DM-RS positions for PUCCH format 3 and 4. + * @param[in] resource Provides the format 3 or 4 resource + * @param[out] idx Destination data for storing the symbol indexes + * @return The number of DMRS symbols if the resource is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_dmrs_pucch_format_3_4_get_symbol_idx(const srslte_pucch_nr_resource_t* resource, + uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB]); + /** * @brief Puts NR-PUCCH format 1 DMRS in the provided resource grid * @param[in] q NR-PUCCH encoder/decoder object diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index b7a8a6f3f..61ee36065 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -64,7 +64,7 @@ extern "C" { #define SRSLTE_LTE_CRC24B 0X1800063 #define SRSLTE_LTE_CRC24C 0X1B2B117 #define SRSLTE_LTE_CRC16 0x11021 -#define SRSLTE_LTE_CRC11 0x621 +#define SRSLTE_LTE_CRC11 0xE21 #define SRSLTE_LTE_CRC8 0x19B #define SRSLTE_LTE_CRC6 0x61 @@ -274,7 +274,7 @@ typedef enum SRSLTE_API { SRSLTE_MIMO_DECODER_ZF, SRSLTE_MIMO_DECODER_MMSE } srs * \brief Types of modulations and associated modulation order. */ typedef enum SRSLTE_API { - SRSLTE_MOD_BPSK = 0, /*!< \brief pi/2-BPSK. */ + SRSLTE_MOD_BPSK = 0, /*!< \brief BPSK. */ SRSLTE_MOD_QPSK, /*!< \brief QPSK. */ SRSLTE_MOD_16QAM, /*!< \brief QAM16. */ SRSLTE_MOD_64QAM, /*!< \brief QAM64. */ diff --git a/lib/include/srslte/phy/phch/pucch_cfg_nr.h b/lib/include/srslte/phy/phch/pucch_cfg_nr.h index 71b21055b..d7ff1ff85 100644 --- a/lib/include/srslte/phy/phch/pucch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/pucch_cfg_nr.h @@ -17,6 +17,54 @@ #include #include +/** + * NR-PUCCH Format 0 ranges + */ +#define SRSLTE_PUCCH_NR_FORMAT0_MAX_CS 11 +#define SRSLTE_PUCCH_NR_FORMAT0_MIN_NSYMB 1 +#define SRSLTE_PUCCH_NR_FORMAT0_MAX_NSYMB 2 +#define SRSLTE_PUCCH_NR_FORMAT0_MAX_STARTSYMB 13 + +/** + * NR-PUCCH Format 1 ranges + */ +#define SRSLTE_PUCCH_NR_FORMAT1_MAX_CS 11 +#define SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC 6 +#define SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB 4 +#define SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB 14 +#define SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB 10 + +/** + * NR-PUCCH Format 2 ranges + */ +#define SRSLTE_PUCCH_NR_FORMAT2_MIN_NPRB 1 +#define SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB 16 +#define SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB 1 +#define SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB 2 +#define SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB 13 + +/** + * NR-PUCCH Format 3 ranges + */ +#define SRSLTE_PUCCH_NR_FORMAT3_MIN_NPRB 1 +#define SRSLTE_PUCCH_NR_FORMAT3_MAX_NPRB 16 +#define SRSLTE_PUCCH_NR_FORMAT3_MIN_NSYMB 4 +#define SRSLTE_PUCCH_NR_FORMAT3_MAX_NSYMB 14 +#define SRSLTE_PUCCH_NR_FORMAT3_MAX_STARTSYMB 10 + +/** + * NR-PUCCH Format 4 ranges + */ +#define SRSLTE_PUCCH_NR_FORMAT4_NPRB 1 +#define SRSLTE_PUCCH_NR_FORMAT4_MIN_NSYMB 4 +#define SRSLTE_PUCCH_NR_FORMAT4_MAX_NSYMB 14 +#define SRSLTE_PUCCH_NR_FORMAT4_MAX_STARTSYMB 10 + +/** + * NR-PUCCH Formats 2, 3 and 4 code rate range + */ +#define SRSLTE_PUCCH_NR_MAX_CODE_RATE 7 + typedef enum SRSLTE_API { SRSLTE_PUCCH_NR_FORMAT_0 = 0, SRSLTE_PUCCH_NR_FORMAT_1, @@ -42,6 +90,10 @@ typedef struct SRSLTE_API { uint32_t hopping_id; ///< Cell-specific scrambling ID for group hopping and sequence hopping if enabled bool hopping_id_present; float p0_nominal; ///< Power control parameter P0 for PUCCH transmissions. Value in dBm. (-202..24) + + // From PUSCH-config + bool scrambling_id_present; + uint32_t scambling_id; // Identifier used to initialize data scrambling (dataScramblingIdentityPUSCH, 0-1023) } srslte_pucch_nr_common_cfg_t; /** @@ -49,7 +101,7 @@ typedef struct SRSLTE_API { * @remark Defined in TS 38.331 PUCCH-Config */ typedef struct SRSLTE_API { - // + // Common PUCCH-Resource parameter uint32_t starting_prb; bool intra_slot_hopping; uint32_t second_hop_prb; @@ -58,36 +110,25 @@ typedef struct SRSLTE_API { srslte_pucch_nr_format_t format; ///< PUCCH format this configuration belongs uint32_t nof_symbols; ///< Number of symbols uint32_t start_symbol_idx; ///< Starting symbol index - double max_code_rate; ///< Maximum code rate (0.08, 0.15, 0.25, 0.35, 0.45, 0.60, 0.80) - bool enable_pi_bpsk; ///< Enables PI-BPSK // Specific PUCCH-Resource uint32_t initial_cyclic_shift; ///< Used by formats 0, 1 uint32_t time_domain_occ; ///< Used by format 1 uint32_t nof_prb; ///< Used by formats 2, 3 - uint32_t occ_lenth; ///< Spreading factor, used by format 4 + uint32_t occ_lenth; ///< Spreading factor, used by format 4 (2, 4). Also called N_PUCCH4_SF uint32_t occ_index; ///< Used by format 4 + + // PUCCH Format common parameters + bool enable_pi_bpsk; ///< Enables PI-BPSK + uint32_t max_code_rate; ///< Maximum code rate r (0..7) + bool additional_dmrs; ///< UE enables 2 DMRS symbols per hop of a PUCCH Format 3 or 4 } srslte_pucch_nr_resource_t; /** - * @brief Validates a PUCCH format 0 resource configuration provided by upper layers + * @brief Validates an NR-PUCCH resource configuration provided by upper layers * @param resource Resource configuration to validate * @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* resource); - -/** - * @brief Validates a PUCCH format 1 resource configuration provided by upper layers - * @param resource Resource configuration to validate - * @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise - */ -SRSLTE_API int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_t* resource); - -/** - * @brief Validates a PUCCH format 2 resource configuration provided by upper layers - * @param resource Resource configuration to validate - * @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise - */ -SRSLTE_API int srslte_pucch_nr_format2_resource_valid(const srslte_pucch_nr_resource_t* resource); +SRSLTE_API int srslte_pucch_nr_cfg_resource_valid(const srslte_pucch_nr_resource_t* resource); #endif // SRSLTE_PUCCH_CFG_NR_H diff --git a/lib/include/srslte/phy/phch/pucch_nr.h b/lib/include/srslte/phy/phch/pucch_nr.h index 94d165488..996867b70 100644 --- a/lib/include/srslte/phy/phch/pucch_nr.h +++ b/lib/include/srslte/phy/phch/pucch_nr.h @@ -53,6 +53,7 @@ typedef struct SRSLTE_API { srslte_modem_table_t qpsk; srslte_uci_nr_t uci; uint8_t* b; + cf_t* d; } srslte_pucch_nr_t; /** diff --git a/lib/include/srslte/phy/phch/ra_ul_nr.h b/lib/include/srslte/phy/phch/ra_ul_nr.h new file mode 100644 index 000000000..510480d9c --- /dev/null +++ b/lib/include/srslte/phy/phch/ra_ul_nr.h @@ -0,0 +1,27 @@ +/** + * + * \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_UL_NR_H +#define SRSLTE_RA_UL_NR_H + +#include "srslte/config.h" +#include "srslte/phy/phch/pucch_cfg_nr.h" +#include "uci_cfg_nr.h" + +/** + * @brief + * @return + */ +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); + +#endif // SRSLTE_RA_UL_NR_H diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index a357e7984..dc24ec7ba 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -13,6 +13,7 @@ #ifndef SRSLTE_UCI_CFG_NR_H #define SRSLTE_UCI_CFG_NR_H +#include "srslte/phy/common/phy_common.h" #include #include @@ -27,6 +28,7 @@ typedef struct SRSLTE_API { uint32_t o_csi1; ///< Number of CSI1 report number of bits uint32_t o_csi2; ///< Number of CSI2 report number of bits srslte_mod_t modulation; ///< Modulation + uint16_t rnti; ///< RNTI } srslte_uci_cfg_nr_t; typedef struct SRSLTE_API { diff --git a/lib/include/srslte/phy/phch/uci_nr.h b/lib/include/srslte/phy/phch/uci_nr.h index 898eb8744..fe1000646 100644 --- a/lib/include/srslte/phy/phch/uci_nr.h +++ b/lib/include/srslte/phy/phch/uci_nr.h @@ -29,7 +29,8 @@ typedef struct { } srslte_uci_nr_args_t; typedef struct { - srslte_polar_rm_t rm; + srslte_polar_rm_t rm_tx; + srslte_polar_rm_t rm_rx; srslte_polar_encoder_t encoder; srslte_polar_decoder_t decoder; srslte_crc_t crc6; @@ -41,6 +42,12 @@ typedef struct { uint8_t* d; ///< Polar code encoded intermediate } srslte_uci_nr_t; +/** + * @brief Calculates in advance how many CRC bits will be appended for a given amount of UCI bits (A) + * @param A Number of UCI bits to transmit + */ +SRSLTE_API uint32_t srslte_uci_nr_crc_len(uint32_t A); + /** * @brief Initialises NR-UCI encoder/decoder object * @param[in,out] q NR-UCI object @@ -90,7 +97,7 @@ SRSLTE_API int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q, SRSLTE_API int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q, const srslte_pucch_nr_resource_t* pucch_resource_cfg, const srslte_uci_cfg_nr_t* uci_cfg, - const int8_t* llr, + int8_t* llr, srslte_uci_value_nr_t* value); #endif // SRSLTE_UCI_NR_H diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index d0661faa4..4e38701c3 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -96,7 +96,7 @@ int srslte_dmrs_pucch_format1_put(const srslte_pucch_nr_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 1 resource\n"); return SRSLTE_ERROR; } @@ -164,7 +164,7 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 1 resource\n"); return SRSLTE_ERROR; } @@ -279,3 +279,101 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q, return SRSLTE_SUCCESS; } + +int srslte_dmrs_pucch_format_3_4_get_symbol_idx(const srslte_pucch_nr_resource_t* resource, + uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB]) +{ + if (resource == NULL || idx == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + int count = 0; + + switch (resource->nof_symbols) { + case 4: + if (resource->intra_slot_hopping) { + idx[count++] = 0; + idx[count++] = 2; + } else { + idx[count++] = 1; + } + break; + case 5: + idx[count++] = 0; + idx[count++] = 3; + break; + case 6: + case 7: + idx[count++] = 1; + idx[count++] = 4; + break; + case 8: + idx[count++] = 1; + idx[count++] = 5; + break; + case 9: + idx[count++] = 1; + idx[count++] = 6; + break; + case 10: + if (resource->additional_dmrs) { + idx[count++] = 1; + idx[count++] = 3; + idx[count++] = 6; + idx[count++] = 8; + } else { + idx[count++] = 2; + idx[count++] = 7; + } + break; + case 11: + if (resource->additional_dmrs) { + idx[count++] = 1; + idx[count++] = 3; + idx[count++] = 6; + idx[count++] = 9; + } else { + idx[count++] = 2; + idx[count++] = 7; + } + break; + case 12: + if (resource->additional_dmrs) { + idx[count++] = 1; + idx[count++] = 4; + idx[count++] = 7; + idx[count++] = 10; + } else { + idx[count++] = 2; + idx[count++] = 8; + } + break; + case 13: + if (resource->additional_dmrs) { + idx[count++] = 1; + idx[count++] = 4; + idx[count++] = 7; + idx[count++] = 11; + } else { + idx[count++] = 2; + idx[count++] = 9; + } + break; + case 14: + if (resource->additional_dmrs) { + idx[count++] = 1; + idx[count++] = 5; + idx[count++] = 8; + idx[count++] = 12; + } else { + idx[count++] = 3; + idx[count++] = 10; + } + break; + default: + ERROR("Invalid case (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + return count; +} diff --git a/lib/src/phy/phch/pucch_cfg_nr.c b/lib/src/phy/phch/pucch_cfg_nr.c index bb58760a9..c52e5d775 100644 --- a/lib/src/phy/phch/pucch_cfg_nr.c +++ b/lib/src/phy/phch/pucch_cfg_nr.c @@ -11,30 +11,28 @@ */ #include "srslte/phy/phch/pucch_cfg_nr.h" +#include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/utils/debug.h" -int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* resource) +static int pucch_nr_cfg_format0_resource_valid(const srslte_pucch_nr_resource_t* resource) { - if (resource == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - if (resource->format != SRSLTE_PUCCH_NR_FORMAT_0) { ERROR("Invalid format (%d)\n", resource->format); return SRSLTE_ERROR; } - if (resource->nof_symbols != 1 && resource->nof_symbols != 2) { + if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT0_MIN_NSYMB || + resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT0_MAX_NSYMB) { ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); return SRSLTE_ERROR; } - if (resource->initial_cyclic_shift > 11) { + if (resource->initial_cyclic_shift > SRSLTE_PUCCH_NR_FORMAT0_MAX_CS) { ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); return SRSLTE_ERROR; } - if (resource->start_symbol_idx > 13) { + if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT0_MAX_STARTSYMB) { ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); return SRSLTE_ERROR; } @@ -42,70 +40,156 @@ int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* res return SRSLTE_SUCCESS; } -int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_t* resource) +static int pucch_nr_cfg_format1_resource_valid(const srslte_pucch_nr_resource_t* resource) { - if (resource == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - if (resource->format != SRSLTE_PUCCH_NR_FORMAT_1) { ERROR("Invalid format (%d)\n", resource->format); return SRSLTE_ERROR; } - if (resource->nof_symbols < 4 || resource->nof_symbols > 14) { + if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB || + resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB) { ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); return SRSLTE_ERROR; } - if (resource->initial_cyclic_shift > 11) { + if (resource->initial_cyclic_shift > SRSLTE_PUCCH_NR_FORMAT1_MAX_CS) { ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); return SRSLTE_ERROR; } - if (resource->start_symbol_idx > 10) { + if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB) { ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); return SRSLTE_ERROR; } - if (resource->time_domain_occ > 6) { + if (resource->time_domain_occ > SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC) { ERROR("Invalid time domain occ (%d)\n", resource->time_domain_occ); return SRSLTE_ERROR; } + return SRSLTE_SUCCESS; +} + +static int pucch_nr_cfg_format2_resource_valid(const srslte_pucch_nr_resource_t* resource) +{ + if (resource->format != SRSLTE_PUCCH_NR_FORMAT_2) { + ERROR("Invalid format (%d)\n", resource->format); + return SRSLTE_ERROR; + } + + if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB || + resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB) { + ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + if (resource->nof_prb < SRSLTE_PUCCH_NR_FORMAT2_MIN_NPRB || resource->nof_prb > SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB) { + ERROR("Invalid number of prb (%d)\n", resource->nof_prb); + return SRSLTE_ERROR; + } + + if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB) { + ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +static int pucch_nr_cfg_format3_resource_valid(const srslte_pucch_nr_resource_t* resource) +{ + if (resource->format != SRSLTE_PUCCH_NR_FORMAT_3) { + ERROR("Invalid format (%d)\n", resource->format); + return SRSLTE_ERROR; + } + + if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT3_MIN_NSYMB || + resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT3_MAX_NSYMB) { + ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + if (resource->nof_prb < SRSLTE_PUCCH_NR_FORMAT3_MIN_NPRB || resource->nof_prb > SRSLTE_PUCCH_NR_FORMAT3_MAX_NPRB) { + ERROR("Invalid number of prb (%d)\n", resource->nof_prb); + return SRSLTE_ERROR; + } + + if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT3_MAX_STARTSYMB) { + ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +static int pucch_nr_cfg_format4_resource_valid(const srslte_pucch_nr_resource_t* resource) +{ + if (resource->format != SRSLTE_PUCCH_NR_FORMAT_4) { + ERROR("Invalid format (%d)\n", resource->format); + return SRSLTE_ERROR; + } + + if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT4_MIN_NSYMB || + resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT4_MAX_NSYMB) { + ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT4_MAX_STARTSYMB) { + ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); + return SRSLTE_ERROR; + } + + if (resource->occ_lenth != 2 && resource->occ_lenth != 4) { + ERROR("Invalid OCC length (%d)\n", resource->occ_lenth); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_pucch_nr_cfg_resource_valid(const srslte_pucch_nr_resource_t* resource) +{ + // Check pointer + if (resource == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (resource->starting_prb > SRSLTE_MAX_NRE_NR - 1) { + return SRSLTE_ERROR; + } + if (resource->intra_slot_hopping) { ERROR("Intra-slot hopping is not implemented\n"); return SRSLTE_ERROR; } - return SRSLTE_SUCCESS; + if (resource->second_hop_prb > SRSLTE_MAX_NRE_NR - 1) { + return SRSLTE_ERROR; + } + + if (resource->max_code_rate > SRSLTE_PUCCH_NR_MAX_CODE_RATE) { + ERROR("Invalid maximum code rate (%d)\n", resource->max_code_rate); + return SRSLTE_ERROR; + } + + switch (resource->format) { + case SRSLTE_PUCCH_NR_FORMAT_0: + return pucch_nr_cfg_format0_resource_valid(resource); + case SRSLTE_PUCCH_NR_FORMAT_1: + return pucch_nr_cfg_format1_resource_valid(resource); + case SRSLTE_PUCCH_NR_FORMAT_2: + return pucch_nr_cfg_format2_resource_valid(resource); + case SRSLTE_PUCCH_NR_FORMAT_3: + return pucch_nr_cfg_format3_resource_valid(resource); + case SRSLTE_PUCCH_NR_FORMAT_4: + return pucch_nr_cfg_format4_resource_valid(resource); + case SRSLTE_PUCCH_NR_FORMAT_ERROR: + default: + ERROR("Invalid case\n"); + break; + } + + return SRSLTE_ERROR; } - -int srslte_pucch_nr_format2_resource_valid(const srslte_pucch_nr_resource_t* resource) -{ - if (resource == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (resource->format != SRSLTE_PUCCH_NR_FORMAT_2) { - ERROR("Invalid format (%d)\n", resource->format); - return SRSLTE_ERROR; - } - - if (resource->nof_symbols < 1 || resource->nof_symbols > 2) { - ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); - return SRSLTE_ERROR; - } - - if (resource->nof_prb < 1 || resource->nof_prb > 16) { - ERROR("Invalid number of prb (%d)\n", resource->nof_prb); - return SRSLTE_ERROR; - } - - if (resource->start_symbol_idx > 13) { - ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); - return SRSLTE_ERROR; - } - - return SRSLTE_SUCCESS; -} \ No newline at end of file diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 2c0b8c189..1ea11638a 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -158,6 +158,13 @@ int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* arg return SRSLTE_ERROR; } + // Allocate encoded symbols d + q->d = srslte_vec_cf_malloc(max_encoded_bits / 2); + if (q->d == NULL) { + ERROR("Malloc\n"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } @@ -167,6 +174,7 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q) return; } + srslte_uci_nr_free(&q->uci); srslte_zc_sequence_lut_free(&q->r_uv_1prb); srslte_modem_table_free(&q->bpsk); @@ -175,6 +183,9 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q) if (q->b != NULL) { free(q->b); } + if (q->d != NULL) { + free(q->d); + } SRSLTE_MEM_ZERO(q, srslte_pucch_nr_t, 1); } @@ -191,7 +202,7 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 0 resource\n"); return SRSLTE_SUCCESS; } @@ -242,7 +253,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 0 resource\n"); return SRSLTE_SUCCESS; } @@ -353,7 +364,7 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 1 resource\n"); return SRSLTE_SUCCESS; } @@ -431,7 +442,7 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q, { uint32_t m_cs = 0; - if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 1 resource\n"); return SRSLTE_SUCCESS; } @@ -501,21 +512,97 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q, return SRSLTE_SUCCESS; } +static uint32_t pucch_nr_format2_cinit(const srslte_pucch_nr_common_cfg_t* pucch_cfg, + const srslte_uci_cfg_nr_t* uci_cfg) +{ + uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : uci_cfg->rnti; + return ((uint32_t)uci_cfg->rnti << 15U) + n_id; +} + +// Implements TS 38.211 section 6.3.2.5 PUCCH format 2 static int pucch_nr_format2_encode(srslte_pucch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_pucch_nr_common_cfg_t* cfg, - const srslte_dl_slot_cfg_t* slot, const srslte_pucch_nr_resource_t* resource, const srslte_uci_cfg_nr_t* uci_cfg, cf_t* slot_symbols) { // Validate configuration - if (srslte_pucch_nr_format2_resource_valid(resource) < SRSLTE_SUCCESS) { + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } - // Implement encode here - // ... + // Calculate number of encoded symbols + uint32_t E = 16 * resource->nof_symbols * resource->nof_prb; + + // 6.3.2.5.1 Scrambling + uint32_t cinit = pucch_nr_format2_cinit(cfg, uci_cfg); + srslte_sequence_apply_bit(q->b, q->b, E, cinit); + + // 6.3.2.5.2 Modulation + srslte_mod_modulate(&q->qpsk, q->b, q->d, E); + + // 6.3.2.5.3 Mapping to physical resources + uint32_t l_start = resource->start_symbol_idx; + uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols; + uint32_t k_start = SRSLTE_MIN(carrier->nof_prb - 1, resource->starting_prb) * SRSLTE_NRE; + uint32_t k_end = SRSLTE_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSLTE_NRE; + for (uint32_t l = l_start, i = 0; l < l_end; l++) { + cf_t* symbol_ptr = &slot_symbols[l * carrier->nof_prb * SRSLTE_NRE]; + for (uint32_t k = k_start; k < k_end; k += 3) { + symbol_ptr[k] = q->d[i++]; + symbol_ptr[k + 2] = q->d[i++]; + } + } + + return SRSLTE_SUCCESS; +} + +static int pucch_nr_format2_decode(srslte_pucch_nr_t* q, + const srslte_carrier_nr_t* carrier, + const srslte_pucch_nr_common_cfg_t* cfg, + const srslte_pucch_nr_resource_t* resource, + const srslte_uci_cfg_nr_t* uci_cfg, + srslte_chest_ul_res_t* chest_res, + cf_t* slot_symbols, + int8_t* llr) +{ + // Validate configuration + if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Calculate number of encoded symbols + uint32_t E = 16 * resource->nof_symbols * resource->nof_prb; + + // Undo mapping to physical resources + uint32_t l_start = resource->start_symbol_idx; + uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols; + uint32_t k_start = resource->starting_prb * SRSLTE_NRE; + uint32_t k_end = (resource->starting_prb + resource->nof_prb) * SRSLTE_NRE; + for (uint32_t l = l_start, i = 0; l < l_end; l++) { + cf_t* symbol_ptr = &slot_symbols[l * carrier->nof_prb * SRSLTE_NRE]; + for (uint32_t k = k_start; k < k_end; k += 3) { + q->d[i++] = symbol_ptr[k]; + q->d[i++] = symbol_ptr[k + 2]; + } + } + + // Equalise + if (srslte_predecoding_single(q->d, chest_res->ce, q->d, NULL, E, 1.0f, chest_res->noise_estimate) < SRSLTE_SUCCESS) { + ERROR("Error Pre-decoding\n"); + return SRSLTE_ERROR; + } + + // Soft-demodulate + if (srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->d, llr, E) < SRSLTE_SUCCESS) { + ERROR("Error soft-demodulate\n"); + return SRSLTE_ERROR; + } + + // Undo Scrambling + uint32_t cinit = pucch_nr_format2_cinit(cfg, uci_cfg); + srslte_sequence_apply_c(llr, llr, E, cinit); return SRSLTE_SUCCESS; } @@ -544,7 +631,7 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q, // Modulate PUCCH switch (resource->format) { case SRSLTE_PUCCH_NR_FORMAT_2: - return pucch_nr_format2_encode(q, carrier, cfg, slot, resource, uci_cfg, slot_symbols); + return pucch_nr_format2_encode(q, carrier, cfg, resource, uci_cfg, slot_symbols); case SRSLTE_PUCCH_NR_FORMAT_3: case SRSLTE_PUCCH_NR_FORMAT_4: ERROR("Not implemented\n"); @@ -557,26 +644,6 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q, return SRSLTE_ERROR; } -static int pucch_nr_format2_decode(srslte_pucch_nr_t* q, - const srslte_carrier_nr_t* carrier, - const srslte_pucch_nr_common_cfg_t* cfg, - const srslte_dl_slot_cfg_t* slot, - const srslte_pucch_nr_resource_t* resource, - srslte_chest_ul_res_t* chest_res, - cf_t* slot_symbols, - int8_t* llr) -{ - // Validate configuration - if (srslte_pucch_nr_format2_resource_valid(resource) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - // Implement decode here - // ... - - return SRSLTE_SUCCESS; -} - int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_pucch_nr_common_cfg_t* cfg, @@ -597,7 +664,11 @@ int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q, int8_t* llr = (int8_t*)q->b; switch (resource->format) { case SRSLTE_PUCCH_NR_FORMAT_2: - return pucch_nr_format2_decode(q, carrier, cfg, slot, resource, chest_res, slot_symbols, llr); + if (pucch_nr_format2_decode(q, carrier, cfg, resource, uci_cfg, chest_res, slot_symbols, llr) < SRSLTE_SUCCESS) { + ERROR("Demodulating PUCCH format 2\n"); + return SRSLTE_ERROR; + } + break; case SRSLTE_PUCCH_NR_FORMAT_3: case SRSLTE_PUCCH_NR_FORMAT_4: ERROR("Not implemented\n"); diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c new file mode 100644 index 000000000..17dbe2fe4 --- /dev/null +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -0,0 +1,158 @@ +/** + * + * \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/phch/ra_ul_nr.h" +#include "srslte/phy/ch_estimation/dmrs_pucch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/debug.h" + +#define RA_UL_PUCCH_CODE_RATE_N 8 +#define RA_UL_PUCCH_CODE_RATE_RESERVED NAN + +static const double ra_ul_pucch_code_rate_table[RA_UL_PUCCH_CODE_RATE_N] = + {0.08, 0.15, 0.25, 0.35, 0.45, 0.60, 0.80, RA_UL_PUCCH_CODE_RATE_RESERVED}; + +// Implements TS 38.213 Table 9.2.5.2-1: Code rate r corresponding to value of maxCodeRate +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"); + return RA_UL_PUCCH_CODE_RATE_RESERVED; + } + + return ra_ul_pucch_code_rate_table[resource->max_code_rate]; +} + +// Calculate number of PRBs for PUCCH format 2, or PUCCH format 3, or PUCCH format 4, respectively +// static int ra_ul_nr_pucch_Mrb(const srslte_pucch_nr_resource_t* resource) +//{ +// switch (resource->format) { +// case SRSLTE_PUCCH_NR_FORMAT_2: +// case SRSLTE_PUCCH_NR_FORMAT_3: +// return resource->nof_prb; +// case SRSLTE_PUCCH_NR_FORMAT_4: +// return SRSLTE_PUCCH_NR_FORMAT4_NPRB; +// default: +// ERROR("Invalid case\n"); +// break; +// } +// return SRSLTE_ERROR; +//} + +// Calculate number of subcarriers per resource block for payload (No DMRS) +static int ra_ul_nr_pucch_nre(const srslte_pucch_nr_resource_t* resource) +{ + switch (resource->format) { + case SRSLTE_PUCCH_NR_FORMAT_2: + return SRSLTE_NRE - 4; + case SRSLTE_PUCCH_NR_FORMAT_3: + return SRSLTE_NRE; + case SRSLTE_PUCCH_NR_FORMAT_4: + return SRSLTE_NRE / resource->occ_lenth; + default: + ERROR("Invalid case\n"); + break; + } + return SRSLTE_ERROR; +} + +// Calculate number of PUCCH symbols excluding the ones used exclusively for DMRS for formats 3 and 4 +static int ra_ul_nr_pucch_nsymb(const srslte_pucch_nr_resource_t* resource) +{ + switch (resource->format) { + case SRSLTE_PUCCH_NR_FORMAT_2: + return resource->nof_symbols; + case SRSLTE_PUCCH_NR_FORMAT_3: + case SRSLTE_PUCCH_NR_FORMAT_4: { + uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB] = {}; + + // Get number of DMRS symbols for format 3 or 4 + int nsymb_dmrs = srslte_dmrs_pucch_format_3_4_get_symbol_idx(resource, idx); + if (nsymb_dmrs < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + return (int)resource->nof_symbols - nsymb_dmrs; + } + default: + ERROR("Invalid case\n"); + break; + } + return SRSLTE_ERROR; +} + +// Calculate number of PUCCH symbols excluding the ones used exclusively for DMRS for formats 3 and 4 +static int ra_ul_nr_pucch_qm(const srslte_pucch_nr_resource_t* resource) +{ + switch (resource->format) { + case SRSLTE_PUCCH_NR_FORMAT_2: + return 2; + case SRSLTE_PUCCH_NR_FORMAT_3: + case SRSLTE_PUCCH_NR_FORMAT_4: + return resource->enable_pi_bpsk ? 1 : 2; + default: + ERROR("Invalid case\n"); + break; + } + return SRSLTE_ERROR; +} + +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) +{ + if (resource == NULL || uci_cfg == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Get maximum allowed code rate + double r = ra_ul_nr_pucch_code_rate_r(resource); + if (!isnormal(r)) { + ERROR("Invalid coderate %f\n", 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"); + return SRSLTE_ERROR; + } + + // Get number of symbols + int nsymb = ra_ul_nr_pucch_nsymb(resource); + if (nsymb < SRSLTE_SUCCESS) { + ERROR("Getting nsymb\n"); + return SRSLTE_ERROR; + } + + // Get modulation order + int qm = ra_ul_nr_pucch_qm(resource); + if (qm < SRSLTE_SUCCESS) { + ERROR("Getting qm\n"); + return SRSLTE_ERROR; + } + + // Calculate denominator + double nof_bits_rb = r * nre * nsymb * qm; + if (!isnormal(nof_bits_rb)) { + return SRSLTE_ERROR; + } + + // Compute total number of UCI bits + uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + uci_cfg->o_csi1 + uci_cfg->o_csi2; + + // Add CRC bits if any + O_total += srslte_uci_nr_crc_len(O_total); + + // Return the minimum + return (int)ceil(O_total / nof_bits_rb); +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/pucch_nr_test.c b/lib/src/phy/phch/test/pucch_nr_test.c index 4600475e0..5d2ce7f0b 100644 --- a/lib/src/phy/phch/test/pucch_nr_test.c +++ b/lib/src/phy/phch/test/pucch_nr_test.c @@ -13,7 +13,9 @@ #include "srslte/common/test_common.h" #include "srslte/phy/ch_estimation/dmrs_pucch.h" #include "srslte/phy/phch/pucch_nr.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" #include #include @@ -30,13 +32,16 @@ static srslte_carrier_nr_t carrier = { 1 // max_mimo_layers }; -static uint32_t starting_prb_stride = 4; -static uint32_t starting_symbol_stride = 4; +static uint32_t starting_prb_stride = 4; +static uint32_t starting_symbol_stride = 4; +static srslte_random_t random_gen = NULL; +static int format = -1; static int test_pucch_format0(srslte_pucch_nr_t* pucch, const srslte_pucch_nr_common_cfg_t* cfg, cf_t* slot_symbols) { - srslte_dl_slot_cfg_t slot = {}; - srslte_pucch_nr_resource_t resource = {}; + srslte_dl_slot_cfg_t slot = {}; + srslte_pucch_nr_resource_t resource = {}; + resource.format = SRSLTE_PUCCH_NR_FORMAT_0; for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb; @@ -83,18 +88,23 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch, srslte_chest_ul_res_t* chest_res, cf_t* slot_symbols) { - srslte_dl_slot_cfg_t slot = {}; - srslte_pucch_nr_resource_t resource = {}; + srslte_dl_slot_cfg_t slot = {}; + srslte_pucch_nr_resource_t resource = {}; + resource.format = SRSLTE_PUCCH_NR_FORMAT_1; for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb; resource.starting_prb += starting_prb_stride) { - for (resource.nof_symbols = 4; resource.nof_symbols <= 14; resource.nof_symbols++) { + for (resource.nof_symbols = SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB; + resource.nof_symbols <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB; + resource.nof_symbols++) { for (resource.start_symbol_idx = 0; - resource.start_symbol_idx <= SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols; + resource.start_symbol_idx <= + SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols); resource.start_symbol_idx += starting_symbol_stride) { - for (resource.time_domain_occ = 0; resource.time_domain_occ <= 6; resource.time_domain_occ++) { - for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11; + for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC; + resource.time_domain_occ++) { + for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSLTE_PUCCH_NR_FORMAT1_MAX_CS; resource.initial_cyclic_shift++) { for (uint32_t nof_bits = 1; nof_bits <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) { for (uint32_t word = 0; word < (1U << nof_bits); word++) { @@ -138,18 +148,103 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch, return SRSLTE_SUCCESS; } +static int test_pucch_format2(srslte_pucch_nr_t* pucch, + const srslte_pucch_nr_common_cfg_t* cfg, + srslte_chest_ul_res_t* chest_res, + cf_t* slot_symbols) +{ + srslte_dl_slot_cfg_t slot = {}; + srslte_pucch_nr_resource_t resource = {}; + resource.format = SRSLTE_PUCCH_NR_FORMAT_2; + + for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { + + for (resource.nof_symbols = SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB; + resource.nof_symbols <= SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB; + resource.nof_symbols++) { + + for (resource.start_symbol_idx = 0; + resource.start_symbol_idx <= + SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB, SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols); + resource.start_symbol_idx += starting_symbol_stride) { + + // Maximum code rate is reserved + for (resource.max_code_rate = 0; resource.max_code_rate < SRSLTE_PUCCH_NR_MAX_CODE_RATE; + resource.max_code_rate++) { + + srslte_uci_cfg_nr_t uci_cfg = {}; + + for (uci_cfg.o_ack = 12; uci_cfg.o_ack <= SRSLTE_UCI_NR_MAX_ACK_BITS; uci_cfg.o_ack++) { + srslte_uci_value_nr_t uci_value = {}; + + // Skip case if not enough PRB are used + int min_nof_prb = srslte_ra_ul_nr_pucch_format_2_3_min_prb(&resource, &uci_cfg); + TESTASSERT(min_nof_prb > SRSLTE_SUCCESS); + + for (resource.nof_prb = min_nof_prb; + resource.nof_prb < SRSLTE_MIN(carrier.nof_prb, SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB); + resource.nof_prb++) { + + for (resource.starting_prb = 0; resource.starting_prb < (carrier.nof_prb - resource.nof_prb); + resource.starting_prb += starting_prb_stride) { + + // Generate ACKs + for (uint32_t i = 0; i < uci_cfg.o_ack; i++) { + uci_value.ack[i] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 1); + } + + // Encode PUCCH + TESTASSERT(srslte_pucch_nr_format_2_3_4_encode( + pucch, &carrier, cfg, &slot, &resource, &uci_cfg, &uci_value, slot_symbols) == + SRSLTE_SUCCESS); + + // Put DMRS + // TESTASSERT(srslte_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, + // slot_symbols) == + // SRSLTE_SUCCESS); + + // Estimate channel + // TESTASSERT(srslte_dmrs_pucch_format1_estimate( + // pucch, &carrier, cfg, &slot, &resource, slot_symbols, chest_res) == + // SRSLTE_SUCCESS); + srslte_chest_ul_res_set_identity(chest_res); + + // Decode PUCCH + srslte_uci_value_nr_t uci_value_rx = {}; + TESTASSERT( + srslte_pucch_nr_format_2_3_4_decode( + pucch, &carrier, cfg, &slot, &resource, &uci_cfg, chest_res, slot_symbols, &uci_value_rx) == + SRSLTE_SUCCESS); + + TESTASSERT(uci_value_rx.valid == true); + + // Check received ACKs + for (uint32_t i = 0; i < uci_cfg.o_ack; i++) { + TESTASSERT(uci_value.ack[i] == uci_value_rx.ack[i]); + } + } + } + } + } + } + } + } + return SRSLTE_SUCCESS; +} + static void usage(char* prog) { printf("Usage: %s [csNnv]\n", prog); printf("\t-c cell id [Default %d]\n", carrier.id); printf("\t-n nof_prb [Default %d]\n", carrier.nof_prb); + printf("\t-f format [Default %d]\n", format); printf("\t-v [set verbose to debug, default none]\n"); } static void parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "cnv")) != -1) { + while ((opt = getopt(argc, argv, "cnfv")) != -1) { switch (opt) { case 'c': carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); @@ -157,6 +252,9 @@ static void parse_args(int argc, char** argv) case 'n': carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; + case 'f': + format = (int)strtol(argv[optind], NULL, 10); + break; case 'v': srslte_verbose++; break; @@ -177,6 +275,12 @@ int main(int argc, char** argv) srslte_pucch_nr_t pucch = {}; srslte_chest_ul_res_t chest_res = {}; + random_gen = srslte_random_init(0x1234); + if (random_gen == NULL) { + ERROR("Random init\n"); + goto clean_exit; + } + if (slot_symb == NULL) { ERROR("Alloc\n"); goto clean_exit; @@ -196,15 +300,27 @@ int main(int argc, char** argv) srslte_pucch_nr_common_cfg_t common_cfg = {}; // Test Format 0 - if (test_pucch_format0(&pucch, &common_cfg, slot_symb) < SRSLTE_SUCCESS) { - ERROR("Failed PUCCH format 0\n"); - goto clean_exit; + if (format < 0 || format == 0) { + if (test_pucch_format0(&pucch, &common_cfg, slot_symb) < SRSLTE_SUCCESS) { + ERROR("Failed PUCCH format 0\n"); + goto clean_exit; + } } // Test Format 1 - if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) { - ERROR("Failed PUCCH format 1\n"); - goto clean_exit; + if (format < 0 || format == 1) { + if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) { + ERROR("Failed PUCCH format 1\n"); + goto clean_exit; + } + } + + // Test Format 2 + if (format < 0 || format == 2) { + if (test_pucch_format2(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) { + ERROR("Failed PUCCH format 2\n"); + goto clean_exit; + } } ret = SRSLTE_SUCCESS; @@ -216,6 +332,8 @@ clean_exit: srslte_pucch_nr_free(&pucch); srslte_chest_ul_res_free(&chest_res); + srslte_random_free(random_gen); + if (ret == SRSLTE_SUCCESS) { printf("Test passed!\n"); } else { diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index c8838cd78..a8a433711 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -17,13 +17,22 @@ #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/vector.h" +#define UCI_NR_INFO_TX(...) INFO("UCI-NR Tx: " __VA_ARGS__) +#define UCI_NR_INFO_RX(...) INFO("UCI-NR Rx: " __VA_ARGS__) + // TS 38.212 section 5.2.1 Polar coding: The value of A is no larger than 1706. #define UCI_NR_MAX_A 1706U #define UCI_NR_MAX_L 11U #define UCI_NR_POLAR_MAX 2048U #define UCI_NR_POLAR_RM_IBIL 0 +#define UCI_NR_PUCCH_POLAR_N_MAX 10 #define UCI_NR_BLOCK_CORR_THRESHOLD 0.5f +uint32_t srslte_uci_nr_crc_len(uint32_t A) +{ + return (A <= 11) ? 0 : (A < 20) ? 6 : 11; +} + int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) { if (q == NULL || args == NULL) { @@ -39,6 +48,11 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) } #endif // LV_HAVE_AVX2 + if (srslte_polar_code_init(&q->code)) { + ERROR("Initialising polar code\n"); + return SRSLTE_ERROR; + } + if (srslte_polar_encoder_init(&q->encoder, polar_encoder_type, NMAX_LOG) < SRSLTE_SUCCESS) { ERROR("Initialising polar encoder\n"); return SRSLTE_ERROR; @@ -49,7 +63,12 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) return SRSLTE_ERROR; } - if (srslte_polar_rm_tx_init(&q->rm) < SRSLTE_SUCCESS) { + if (srslte_polar_rm_tx_init(&q->rm_tx) < SRSLTE_SUCCESS) { + ERROR("Initialising polar RM\n"); + return SRSLTE_ERROR; + } + + if (srslte_polar_rm_rx_init_c(&q->rm_rx) < SRSLTE_SUCCESS) { ERROR("Initialising polar RM\n"); return SRSLTE_ERROR; } @@ -99,8 +118,11 @@ void srslte_uci_nr_free(srslte_uci_nr_t* q) return; } + srslte_polar_code_free(&q->code); srslte_polar_encoder_free(&q->encoder); srslte_polar_decoder_free(&q->decoder); + srslte_polar_rm_tx_free(&q->rm_tx); + srslte_polar_rm_rx_free_c(&q->rm_rx); if (q->bit_sequence != NULL) { free(q->bit_sequence); @@ -130,6 +152,11 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v srslte_vec_u8_copy(&sequence[A], value->sr, cfg->o_sr); A += cfg->o_sr; + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Packed UCI bits: "); + srslte_vec_fprint_byte(stdout, sequence, A); + } + return A; } @@ -145,6 +172,11 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr); A += cfg->o_sr; + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Unpacked UCI bits: "); + srslte_vec_fprint_byte(stdout, sequence, A); + } + return A; } @@ -356,11 +388,11 @@ static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg static int uci_nr_encode_3_11_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E) { - uint8_t encoded[SRSLTE_FEC_BLOCK_SIZE] = {}; - srslte_block_encode(q->bit_sequence, A, encoded, SRSLTE_FEC_BLOCK_SIZE); + srslte_block_encode(q->bit_sequence, A, o, E); - for (uint32_t i = 0; i < E; i++) { - o[i] = (encoded[i % SRSLTE_FEC_BLOCK_SIZE] == 0) ? UCI_BIT_0 : UCI_BIT_1; + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Block encoded UCI bits; o="); + srslte_vec_fprint_b(stdout, o, E); } return E; @@ -384,6 +416,11 @@ static int uci_nr_decode_3_11_bit(srslte_uci_nr_t* q, return SRSLTE_ERROR; } + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Block decoding NR-UCI llr="); + srslte_vec_fprint_bs(stdout, llr, E); + } + // Decode float corr = (float)srslte_block_decode_i8(llr, E, q->bit_sequence, A); @@ -408,10 +445,8 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui } // Select CRC - srslte_crc_t* crc = &q->crc6; - if (A >= 20) { - crc = &q->crc11; - } + uint32_t L = srslte_uci_nr_crc_len(A); + srslte_crc_t* crc = (L == 6) ? &q->crc6 : &q->crc11; // Segmentation uint32_t C = 1; @@ -421,9 +456,9 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui uint32_t A_prime = CEIL(A, C) * C; // Get polar code - uint32_t K_r = A_prime / C + crc->order; + uint32_t K_r = A_prime / C + L; uint32_t E_r = E_uci / C; - if (srslte_polar_code_get(&q->code, K_r, E_r, 9U) < SRSLTE_SUCCESS) { + if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } @@ -445,17 +480,33 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui // Attach CRC srslte_crc_attach(crc, q->c, A_prime / C); + UCI_NR_INFO_TX("Attaching %d/%d CRC%d=%02lx\n", r, C, L, srslte_crc_checksum_get(crc)); + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Polar cb %d/%d c=", r, C); + srslte_vec_fprint_byte(stdout, q->c, K_r); + } // Allocate channel srslte_polar_chanalloc_tx(q->c, q->allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Polar alloc %d/%d ", r, C); + srslte_vec_fprint_byte(stdout, q->allocated, q->code.N); + } + // Encode bits if (srslte_polar_encoder_encode(&q->encoder, q->allocated, q->d, q->code.n) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } // Rate matching - srslte_polar_rm_tx(&q->rm, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL); + srslte_polar_rm_tx(&q->rm_tx, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL); + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Polar cw %d/%d ", r, C); + srslte_vec_fprint_byte(stdout, &o[E_r * r], q->code.N); + } } return E_uci; @@ -464,7 +515,7 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, - const int8_t* llr, + int8_t* llr, uint32_t E_uci, bool* decoded_ok) { @@ -477,10 +528,8 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q, } // Select CRC - srslte_crc_t* crc = &q->crc6; - if (A >= 20) { - crc = &q->crc11; - } + uint32_t L = srslte_uci_nr_crc_len(A); + srslte_crc_t* crc = (L == 6) ? &q->crc6 : &q->crc11; // Segmentation uint32_t C = 1; @@ -490,19 +539,29 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q, uint32_t A_prime = CEIL(A, C) * C; // Get polar code - uint32_t K_r = A_prime / C + crc->order; + uint32_t K_r = A_prime / C + L; uint32_t E_r = E_uci / C; - if (srslte_polar_code_get(&q->code, K_r, E_r, 9U) < SRSLTE_SUCCESS) { + if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + // Negate all LLR + for (uint32_t i = 0; i < E_r; i++) { + llr[i] *= -1; + } + // Write codeword for (uint32_t r = 0, s = 0; r < C; r++) { uint32_t k = 0; + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Polar LLR %d/%d ", r, C); + srslte_vec_fprint_bs(stdout, &llr[E_r * r], q->code.N); + } + // Undo rate matching int8_t* d = (int8_t*)q->d; - srslte_polar_rm_rx_c(&q->rm, &llr[E_r * r], d, q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL); + srslte_polar_rm_rx_c(&q->rm_rx, &llr[E_r * r], d, E_r, q->code.n, K_r, UCI_NR_POLAR_RM_IBIL); // Decode bits if (srslte_polar_decoder_decode_c(&q->decoder, d, q->allocated, q->code.n, q->code.F_set, q->code.F_set_size) < @@ -510,14 +569,25 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q, return SRSLTE_ERROR; } + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Polar alloc %d/%d ", r, C); + srslte_vec_fprint_byte(stdout, q->allocated, q->code.N); + } + // Undo channel allocation srslte_polar_chanalloc_rx(q->allocated, q->c, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); - // - uint8_t* ptr = &q->c[q->code.K - crc->order]; - uint32_t checksum1 = srslte_crc_checksum(crc, q->c, q->code.K); - uint32_t checksum2 = srslte_bit_pack(&ptr, crc->order); + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Polar cb %d/%d c=", r, C); + srslte_vec_fprint_byte(stdout, q->c, K_r); + } + + // Calculate checksum + uint8_t* ptr = &q->c[A_prime / C]; + uint32_t checksum1 = srslte_crc_checksum(crc, q->c, A_prime / C); + uint32_t checksum2 = srslte_bit_pack(&ptr, L); (*decoded_ok) = ((*decoded_ok) && (checksum1 == checksum2)); + UCI_NR_INFO_RX("Checking %d/%d CRC%d={%02x,%02x}\n", r, C, L, checksum1, checksum2); // Prefix (A_prime - A) zeros for the first CB only if (r == 0) { @@ -577,7 +647,7 @@ static int uci_nr_encode(srslte_uci_nr_t* q, static int uci_nr_decode(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* uci_cfg, - const int8_t* llr, + int8_t* llr, uint32_t E_uci, srslte_uci_value_nr_t* uci_value) { @@ -624,20 +694,9 @@ static int uci_nr_pucch_E_tot(const srslte_pucch_nr_resource_t* pucch_cfg, const return SRSLTE_ERROR_INVALID_INPUTS; } - // Compute total number of bits - uint32_t nof_bits = uci_cfg->o_sr + uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2; - switch (pucch_cfg->format) { - case SRSLTE_PUCCH_NR_FORMAT_1: - if (nof_bits <= 2) { - return nof_bits; - } - break; case SRSLTE_PUCCH_NR_FORMAT_2: - if (uci_cfg->modulation == SRSLTE_MOD_QPSK) { - return (int)(16 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb); - } - break; + return (int)(16 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb); case SRSLTE_PUCCH_NR_FORMAT_3: if (uci_cfg->modulation == SRSLTE_MOD_QPSK) { return (int)(24 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb); @@ -684,11 +743,13 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q, { int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg); if (E_tot < SRSLTE_SUCCESS) { + ERROR("Error calculating number of bits\n"); return SRSLTE_ERROR; } int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot); if (E_uci < SRSLTE_SUCCESS) { + ERROR("Error calculating number of bits\n"); return SRSLTE_ERROR; } @@ -698,7 +759,7 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q, int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q, const srslte_pucch_nr_resource_t* pucch_resource_cfg, const srslte_uci_cfg_nr_t* uci_cfg, - const int8_t* llr, + int8_t* llr, srslte_uci_value_nr_t* value) { int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg);