From 4d96cf4a418c13ba3bf104f0f5dca5ce6ae2999f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 19 Jan 2021 15:25:18 +0100 Subject: [PATCH] More NR-PUCCH support --- .../srslte/phy/ch_estimation/dmrs_pucch.h | 26 +- lib/include/srslte/phy/phch/pucch_cfg_nr.h | 86 ++++++ lib/include/srslte/phy/phch/pucch_nr.h | 131 ++------- lib/include/srslte/phy/phch/uci_cfg_nr.h | 2 +- lib/include/srslte/phy/phch/uci_nr.h | 8 +- lib/include/srslte/phy/utils/vector.h | 1 + lib/src/phy/ch_estimation/dmrs_pucch.c | 28 +- lib/src/phy/phch/pucch_cfg_nr.c | 82 ++++++ lib/src/phy/phch/pucch_nr.c | 168 +++++------ lib/src/phy/phch/test/pucch_nr_test.c | 7 +- lib/src/phy/phch/uci_nr.c | 267 ++++++++++++++++-- lib/src/phy/utils/vector.c | 22 ++ 12 files changed, 585 insertions(+), 243 deletions(-) create mode 100644 lib/include/srslte/phy/phch/pucch_cfg_nr.h create mode 100644 lib/src/phy/phch/pucch_cfg_nr.c diff --git a/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h b/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h index 9c0ee006b..b6689069c 100644 --- a/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h +++ b/lib/include/srslte/phy/ch_estimation/dmrs_pucch.h @@ -27,12 +27,12 @@ * @param[out] slot_symbols Resource grid of the given slot * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_dmrs_pucch_format1_put(const 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_format1_t* resource, - cf_t* slot_symbols); +SRSLTE_API int srslte_dmrs_pucch_format1_put(const 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, + cf_t* slot_symbols); /** * @brief Estimates NR-PUCCH format 1 resource elements from their DMRS in the provided resource grid @@ -45,12 +45,12 @@ SRSLTE_API int srslte_dmrs_pucch_format1_put(const srslte_pucch_nr_t* * @param[out] res UL Channel estimator result * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_dmrs_pucch_format1_estimate(const 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_format1_t* resource, - const cf_t* slot_symbols, - srslte_chest_ul_res_t* res); +SRSLTE_API int srslte_dmrs_pucch_format1_estimate(const 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 cf_t* slot_symbols, + srslte_chest_ul_res_t* res); #endif // SRSLTE_DMRS_PUCCH_H diff --git a/lib/include/srslte/phy/phch/pucch_cfg_nr.h b/lib/include/srslte/phy/phch/pucch_cfg_nr.h new file mode 100644 index 000000000..6a7864973 --- /dev/null +++ b/lib/include/srslte/phy/phch/pucch_cfg_nr.h @@ -0,0 +1,86 @@ +/** + * + * \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_PUCCH_CFG_NR_H +#define SRSLTE_PUCCH_CFG_NR_H + +#include "srslte/config.h" +#include +#include + +typedef enum SRSLTE_API { + SRSLTE_PUCCH_NR_FORMAT_0 = 0, + SRSLTE_PUCCH_NR_FORMAT_1, + SRSLTE_PUCCH_NR_FORMAT_2, + SRSLTE_PUCCH_NR_FORMAT_3, + SRSLTE_PUCCH_NR_FORMAT_4, + SRSLTE_PUCCH_NR_FORMAT_ERROR, +} srslte_pucch_nr_format_t; + +typedef enum SRSLTE_API { + SRSLTE_PUCCH_NR_GROUP_HOPPING_NEITHER = 0, + SRSLTE_PUCCH_NR_GROUP_HOPPING_ENABLE, + SRSLTE_PUCCH_NR_GROUP_HOPPING_DISABLE +} srslte_pucch_nr_group_hopping_t; + +/** + * @brief PUCCH Common configuration + * @remark Defined in TS 38.331 PUCCH-ConfigCommon + */ +typedef struct SRSLTE_API { + uint32_t resource_common; ///< Configures a set of cell-specific PUCCH resources/parameters + srslte_pucch_nr_group_hopping_t group_hopping; ///< Configuration of group and sequence hopping + 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) +} srslte_pucch_nr_common_cfg_t; + +/** + * @brief Generic PUCCH Resource configuration + * @remark Defined in TS 38.331 PUCCH-Config + */ +typedef struct SRSLTE_API { + // + uint32_t starting_prb; + bool intra_slot_hopping; + uint32_t second_hop_prb; + + // Common PUCCH-Resource parameters among all formats + 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_index; ///< Used by format 4 +} srslte_pucch_nr_resource_t; + +/** + * @brief Validates a PUCCH format 0 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); + +#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 15f0d418f..9a1a6397d 100644 --- a/lib/include/srslte/phy/phch/pucch_nr.h +++ b/lib/include/srslte/phy/phch/pucch_nr.h @@ -17,6 +17,7 @@ #include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/common/zc_sequence.h" #include "srslte/phy/modem/modem_table.h" +#include "srslte/phy/phch/uci_nr.h" #include #include #include @@ -31,57 +32,10 @@ */ #define SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS 2 -typedef enum SRSLTE_API { - SRSLTE_PUCCH_NR_FORMAT_0 = 0, - SRSLTE_PUCCH_NR_FORMAT_1, - SRSLTE_PUCCH_NR_FORMAT_2, - SRSLTE_PUCCH_NR_FORMAT_3, - SRSLTE_PUCCH_NR_FORMAT_4, - SRSLTE_PUCCH_NR_FORMAT_ERROR, -} srslte_pucch_nr_format_t; - -typedef enum SRSLTE_API { - SRSLTE_PUCCH_NR_GROUP_HOPPING_NEITHER = 0, - SRSLTE_PUCCH_NR_GROUP_HOPPING_ENABLE, - SRSLTE_PUCCH_NR_GROUP_HOPPING_DISABLE -} srslte_pucch_nr_group_hopping_t; - -/** - * @brief PUCCH Common configuration - * @remark Defined in TS 38.331 PUCCH-ConfigCommon - */ typedef struct SRSLTE_API { - uint32_t resource_common; ///< Configures a set of cell-specific PUCCH resources/parameters - srslte_pucch_nr_group_hopping_t group_hopping; ///< Configuration of group and sequence hopping - 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) -} srslte_pucch_nr_common_cfg_t; - -/** - * @brief Generic PUCCH Resource configuration - * @remark Defined in TS 38.331 PUCCH-Config - */ -typedef struct SRSLTE_API { - // - uint32_t starting_prb; - bool intra_slot_frequency_hopping; - uint32_t second_hop_prb; - - // Common PUCCH-Resource parameters among all formats - 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_index; ///< Used by format 4 -} srslte_pucch_nr_resource_t; + srslte_uci_nr_args_t uci; + uint32_t max_nof_prb; +} srslte_pucch_nr_args_t; typedef struct SRSLTE_API { float rsrp; @@ -91,38 +45,17 @@ typedef struct SRSLTE_API { float norm_corr; } srslte_pucch_nr_measure_t; -/** - * @brief PUCCH Resource configuration for Format 0 - * @remark Defined in TS 38.331 PUCCH-Config - */ -typedef struct SRSLTE_API { - uint32_t starting_prb; - uint32_t initial_cyclic_shift; ///< initialCyclicShift (0..11) - uint32_t start_symbol_idx; ///< startingSymbolIndex (0..13) - uint32_t nof_symbols; ///< nrofSymbols (1..2) -} srslte_pucch_nr_resource_format0_t; - -/** - * @brief PUCCH Resource configuration for Format 1 - * @remark Defined in TS 38.331 PUCCH-Config - */ -typedef struct SRSLTE_API { - uint32_t starting_prb; - uint32_t initial_cyclic_shift; ///< initialCyclicShift (0..11) - uint32_t start_symbol_idx; ///< startingSymbolIndex (0..10) - uint32_t nof_symbols; ///< nrofSymbols (4..14) - uint32_t time_domain_occ; ///< TimeDomainOCC(0..6) - bool intra_slot_hopping; -} srslte_pucch_nr_resource_format1_t; - /** * @brief NR-PUCCH encoder/decoder object */ typedef struct SRSLTE_API { + uint32_t max_prb; srslte_zc_sequence_lut_t r_uv_1prb; cf_t format1_w_i_m[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX]; srslte_modem_table_t bpsk; srslte_modem_table_t qpsk; + srslte_uci_nr_t uci; + uint8_t* b; } srslte_pucch_nr_t; /** @@ -130,7 +63,7 @@ typedef struct SRSLTE_API { * @param q Object * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_pucch_nr_init(srslte_pucch_nr_t* q); +SRSLTE_API int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* args); /** * @brief Deallocates an NR-PUCCH encoder/decoder object @@ -173,13 +106,6 @@ SRSLTE_API int srslte_pucch_nr_alpha_idx(const srslte_carrier_nr_t* car uint32_t m_cs, uint32_t* alpha_idx); -/** - * @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_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource); - /** * @brief Encode and writes NR-PUCCH format 0 in the resource grid * @remark Described in TS 38.211 clause 6.3.2.3 PUCCH format 0 @@ -196,7 +122,7 @@ SRSLTE_API int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* const srslte_carrier_nr_t* carrier, const srslte_pucch_nr_common_cfg_t* cfg, const srslte_dl_slot_cfg_t* slot, - srslte_pucch_nr_resource_format0_t* resource, + srslte_pucch_nr_resource_t* resource, uint32_t m_cs, cf_t* slot_symbols); @@ -216,18 +142,11 @@ SRSLTE_API int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* const srslte_carrier_nr_t* carrier, const srslte_pucch_nr_common_cfg_t* cfg, const srslte_dl_slot_cfg_t* slot, - srslte_pucch_nr_resource_format0_t* resource, + srslte_pucch_nr_resource_t* resource, uint32_t m_cs, const cf_t* slot_symbols, srslte_pucch_nr_measure_t* measure); -/** - * @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_format1_t* resource); - /** * @brief Get NR-PUCCH orthogonal sequence w * @remark Defined by TS 38.211 Table 6.3.2.4.1-2: Orthogonal sequences ... for PUCCH format 1 @@ -252,14 +171,14 @@ SRSLTE_API cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n * @param[out] slot_symbols Resource grid of the given slot * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_pucch_nr_format1_encode(const 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_format1_t* resource, - uint8_t* b, - uint32_t nof_bits, - cf_t* slot_symbols); +SRSLTE_API int srslte_pucch_nr_format1_encode(const 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, + uint8_t* b, + uint32_t nof_bits, + cf_t* slot_symbols); /** * @brief Decodes NR-PUCCH format 1 @@ -274,13 +193,13 @@ SRSLTE_API int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* * @param[in] nof_bits Number of bits to decode in the message * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise */ -SRSLTE_API int srslte_pucch_nr_format1_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_format1_t* resource, - srslte_chest_ul_res_t* chest_res, - cf_t* slot_symbols, +SRSLTE_API int srslte_pucch_nr_format1_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, uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS], uint32_t nof_bits); diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index 0f47924d9..a357e7984 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -16,7 +16,7 @@ #include #include -#define SRSLTE_UCI_NR_MAX_ACK_BITS 10 +#define SRSLTE_UCI_NR_MAX_ACK_BITS 360 #define SRSLTE_UCI_NR_MAX_SR_BITS 10 #define SRSLTE_UCI_NR_MAX_CSI1_BITS 10 #define SRSLTE_UCI_NR_MAX_CSI2_BITS 10 diff --git a/lib/include/srslte/phy/phch/uci_nr.h b/lib/include/srslte/phy/phch/uci_nr.h index 5c7600493..8d31c3124 100644 --- a/lib/include/srslte/phy/phch/uci_nr.h +++ b/lib/include/srslte/phy/phch/uci_nr.h @@ -15,9 +15,10 @@ #include "srslte/phy/fec/crc.h" #include "srslte/phy/fec/polar/polar_code.h" +#include "srslte/phy/fec/polar/polar_decoder.h" #include "srslte/phy/fec/polar/polar_encoder.h" #include "srslte/phy/fec/polar/polar_rm.h" -#include "srslte/phy/phch/pucch_nr.h" +#include "srslte/phy/phch/pucch_cfg_nr.h" #include "uci_cfg.h" #include "uci_cfg_nr.h" #include @@ -27,13 +28,10 @@ typedef struct { bool disable_simd; } srslte_uci_nr_args_t; -typedef struct { - -} srslte_uci_nr_cfg_t; - typedef struct { srslte_polar_rm_t rm; srslte_polar_encoder_t encoder; + srslte_polar_decoder_t decoder; srslte_crc_t crc6; srslte_crc_t crc11; srslte_polar_code_t code; diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 35dcb7c95..039e070f4 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -194,6 +194,7 @@ SRSLTE_API void srslte_vec_conj_cc(const cf_t* x, cf_t* y, const uint32_t len); /* average vector power */ SRSLTE_API float srslte_vec_avg_power_cf(const cf_t* x, const uint32_t len); SRSLTE_API float srslte_vec_avg_power_sf(const int16_t* x, const uint32_t len); +SRSLTE_API float srslte_vec_avg_power_bf(const int8_t* x, const uint32_t len); /* Correlation between complex vectors x and y */ SRSLTE_API float srslte_vec_corr_ccc(const cf_t* x, cf_t* y, const uint32_t len); diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index daf0150e4..d0661faa4 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -15,7 +15,7 @@ #include "srslte/phy/utils/vector.h" // Implements TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_PUCCH... -static uint32_t dmrs_pucch_format1_n_pucch(const srslte_pucch_nr_resource_format1_t* resource, uint32_t m_prime) +static uint32_t dmrs_pucch_format1_n_pucch(const srslte_pucch_nr_resource_t* resource, uint32_t m_prime) { if (resource->intra_slot_hopping) { if (m_prime == 0) { @@ -84,12 +84,12 @@ static uint32_t dmrs_pucch_format1_n_pucch(const srslte_pucch_nr_resource_format return 0; } -int srslte_dmrs_pucch_format1_put(const 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_format1_t* resource, - cf_t* slot_symbols) +int srslte_dmrs_pucch_format1_put(const 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, + cf_t* slot_symbols) { if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) { @@ -151,13 +151,13 @@ int srslte_dmrs_pucch_format1_put(const srslte_pucch_nr_t* q, return SRSLTE_SUCCESS; } -int srslte_dmrs_pucch_format1_estimate(const 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_format1_t* resource, - const cf_t* slot_symbols, - srslte_chest_ul_res_t* res) +int srslte_dmrs_pucch_format1_estimate(const 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 cf_t* slot_symbols, + srslte_chest_ul_res_t* res) { if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) { diff --git a/lib/src/phy/phch/pucch_cfg_nr.c b/lib/src/phy/phch/pucch_cfg_nr.c new file mode 100644 index 000000000..174d11e48 --- /dev/null +++ b/lib/src/phy/phch/pucch_cfg_nr.c @@ -0,0 +1,82 @@ +/** + * + * \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/pucch_cfg_nr.h" +#include "srslte/phy/utils/debug.h" + +int srslte_pucch_nr_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) { + ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + if (resource->initial_cyclic_shift > 11) { + ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); + 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; +} + +int srslte_pucch_nr_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) { + ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); + return SRSLTE_ERROR; + } + + if (resource->initial_cyclic_shift > 11) { + ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); + return SRSLTE_ERROR; + } + + if (resource->start_symbol_idx > 10) { + ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); + return SRSLTE_ERROR; + } + + if (resource->time_domain_occ > 6) { + ERROR("Invalid time domain occ (%d)\n", resource->time_domain_occ); + return SRSLTE_ERROR; + } + + if (resource->intra_slot_hopping) { + ERROR("Intra-slot hopping is not implemented\n"); + 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 49851a1a5..a77837d0e 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -90,64 +90,6 @@ int srslte_pucch_nr_alpha_idx(const srslte_carrier_nr_t* carrier, return SRSLTE_SUCCESS; } -int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource) -{ - if (resource == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (resource->nof_symbols != 1 && resource->nof_symbols != 2) { - ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); - return SRSLTE_ERROR; - } - - if (resource->initial_cyclic_shift > 11) { - ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); - 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; -} - -int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_format1_t* resource) -{ - if (resource == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (resource->nof_symbols < 4 || resource->nof_symbols > 14) { - ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols); - return SRSLTE_ERROR; - } - - if (resource->initial_cyclic_shift > 11) { - ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift); - return SRSLTE_ERROR; - } - - if (resource->start_symbol_idx > 10) { - ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx); - return SRSLTE_ERROR; - } - - if (resource->time_domain_occ > 6) { - ERROR("Invalid time domain occ (%d)\n", resource->time_domain_occ); - return SRSLTE_ERROR; - } - - if (resource->intra_slot_hopping) { - ERROR("Intra-slot hopping is not implemented\n"); - return SRSLTE_ERROR; - } - - return SRSLTE_SUCCESS; -} - // TS 38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH format 1 static uint32_t pucch_nr_format1_rho[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX] = @@ -159,12 +101,21 @@ static uint32_t {{}, {}, {}, {}, {}, {0, 5, 4, 3, 2, 1}, {0, 5, 3, 1, 6, 4, 2}}, {{}, {}, {}, {}, {}, {}, {0, 6, 5, 4, 3, 2, 1}}}; -int srslte_pucch_nr_init(srslte_pucch_nr_t* q) +int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* args) { - if (q == NULL) { + if (q == NULL || args == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } + // Make sure object is zeroed + SRSLTE_MEM_ZERO(q, srslte_pucch_nr_t, 1); + + // Save maximum number of PRB + q->max_prb = SRSLTE_MAX_PRB_NR; + if (args->max_nof_prb != 0) { + q->max_prb = args->max_nof_prb; + } + // Initialise ZC sequences for 1PRB float alphas_1prb[SRSLTE_NRE] = {}; for (uint32_t i = 0; i < SRSLTE_NRE; i++) { @@ -193,6 +144,19 @@ int srslte_pucch_nr_init(srslte_pucch_nr_t* q) } } + if (srslte_uci_nr_init(&q->uci, &args->uci) < SRSLTE_SUCCESS) { + ERROR("Initiating UCI encoder/decoder\n"); + return SRSLTE_ERROR; + } + + // Allocate encoded bits b + uint32_t max_encoded_bits = q->max_prb * SRSLTE_NRE * 2 * SRSLTE_NSYMB_PER_SLOT_NR; // Assumes QPSK (Qm = 2) + q->b = srslte_vec_u8_malloc(max_encoded_bits); + if (q->b == NULL) { + ERROR("Malloc\n"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } @@ -207,6 +171,10 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q) srslte_modem_table_free(&q->bpsk); srslte_modem_table_free(&q->qpsk); + if (q->b != NULL) { + free(q->b); + } + SRSLTE_MEM_ZERO(q, srslte_pucch_nr_t, 1); } @@ -214,7 +182,7 @@ int srslte_pucch_nr_format0_encode(const 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, - srslte_pucch_nr_resource_format0_t* resource, + srslte_pucch_nr_resource_t* resource, uint32_t m_cs, cf_t* slot_symbols) { @@ -264,7 +232,7 @@ int srslte_pucch_nr_format0_measure(const 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, - srslte_pucch_nr_resource_format0_t* resource, + srslte_pucch_nr_resource_t* resource, uint32_t m_cs, const cf_t* slot_symbols, srslte_pucch_nr_measure_t* measure) @@ -333,7 +301,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q, } // Implements TS 38.211 table 6.3.2.4.1-1 Number of PUCCH symbols and the corresponding N_PUC... -static uint32_t pucch_nr_format1_n_pucch(const srslte_pucch_nr_resource_format1_t* resource, uint32_t m_prime) +static uint32_t pucch_nr_format1_n_pucch(const srslte_pucch_nr_resource_t* resource, uint32_t m_prime) { if (resource->intra_slot_hopping) { if (m_prime == 0) { @@ -369,14 +337,14 @@ cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n_pucch, uin return q->format1_w_i_m[i][n_pucch - 1][m]; } -int srslte_pucch_nr_format1_encode(const 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_format1_t* resource, - uint8_t* b, - uint32_t nof_bits, - cf_t* slot_symbols) +int srslte_pucch_nr_format1_encode(const 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, + uint8_t* b, + uint32_t nof_bits, + cf_t* slot_symbols) { uint32_t m_cs = 0; @@ -450,22 +418,18 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q, return SRSLTE_SUCCESS; } -int srslte_pucch_nr_format1_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_format1_t* resource, - srslte_chest_ul_res_t* chest_res, - cf_t* slot_symbols, - uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS], - uint32_t nof_bits) +int srslte_pucch_nr_format1_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, + uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS], + uint32_t nof_bits) { uint32_t m_cs = 0; - if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || b == NULL || slot_symbols == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) { ERROR("Invalid PUCCH format 1 resource\n"); return SRSLTE_SUCCESS; @@ -533,5 +497,41 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q, b[i] = llr[i] > 0.0f ? 1 : 0; } + return SRSLTE_SUCCESS; +} + +int srslte_pucch_nr_format_2_3_4_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, + const srslte_uci_value_nr_t* uci_value, + cf_t* slot_symbols) +{ + if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || uci_cfg == NULL || + uci_value == NULL || slot_symbols == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (srslte_uci_nr_encode_pucch(&q->uci, resource, uci_cfg, uci_value, q->b) < SRSLTE_SUCCESS) { + ERROR("Error encoding UCI\n"); + return SRSLTE_ERROR; + } + + // Encode PUCCH + switch (resource->format) { + case SRSLTE_PUCCH_NR_FORMAT_2: + break; + case SRSLTE_PUCCH_NR_FORMAT_3: + case SRSLTE_PUCCH_NR_FORMAT_4: + ERROR("Not implemented\n"); + return SRSLTE_ERROR; + default: + case SRSLTE_PUCCH_NR_FORMAT_ERROR: + ERROR("Invalid format\n"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } \ 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 2594615e2..4600475e0 100644 --- a/lib/src/phy/phch/test/pucch_nr_test.c +++ b/lib/src/phy/phch/test/pucch_nr_test.c @@ -36,7 +36,7 @@ static uint32_t starting_symbol_stride = 4; 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_format0_t resource = {}; + srslte_pucch_nr_resource_t resource = {}; 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; @@ -84,7 +84,7 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch, cf_t* slot_symbols) { srslte_dl_slot_cfg_t slot = {}; - srslte_pucch_nr_resource_format1_t resource = {}; + srslte_pucch_nr_resource_t resource = {}; 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; @@ -182,7 +182,8 @@ int main(int argc, char** argv) goto clean_exit; } - if (srslte_pucch_nr_init(&pucch) < SRSLTE_SUCCESS) { + srslte_pucch_nr_args_t pucch_args = {}; + if (srslte_pucch_nr_init(&pucch, &pucch_args) < SRSLTE_SUCCESS) { ERROR("PUCCH init\n"); goto clean_exit; } diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index 093ada5f7..84b56d136 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -14,13 +14,15 @@ #include "srslte/phy/fec/block/block.h" #include "srslte/phy/fec/polar/polar_chanalloc.h" #include "srslte/phy/phch/uci_cfg.h" +#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/vector.h" // TS 38.212 section 5.2.1 Polar coding: The value of A is no larger than 1706. -#define UCI_NR_MAX_A 1906U +#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_BLOCK_CORR_THRESHOLD 0.5f int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) { @@ -29,9 +31,11 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) } srslte_polar_encoder_type_t polar_encoder_type = SRSLTE_POLAR_ENCODER_PIPELINED; + srslte_polar_decoder_type_t polar_decoder_type = SRSLTE_POLAR_DECODER_SSC_C; #ifdef LV_HAVE_AVX2 if (!args->disable_simd) { polar_encoder_type = SRSLTE_POLAR_ENCODER_AVX2; + polar_decoder_type = SRSLTE_POLAR_DECODER_SSC_C_AVX2; } #endif // LV_HAVE_AVX2 @@ -40,6 +44,11 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args) return SRSLTE_ERROR; } + if (srslte_polar_decoder_init(&q->decoder, polar_decoder_type, NMAX_LOG) < SRSLTE_SUCCESS) { + ERROR("Initialising polar encoder\n"); + return SRSLTE_ERROR; + } + if (srslte_polar_rm_tx_init(&q->rm) < SRSLTE_SUCCESS) { ERROR("Initialising polar RM\n"); return SRSLTE_ERROR; @@ -91,6 +100,7 @@ void srslte_uci_nr_free(srslte_uci_nr_t* q) } srslte_polar_encoder_free(&q->encoder); + srslte_polar_decoder_free(&q->decoder); if (q->bit_sequence != NULL) { free(q->bit_sequence); @@ -108,8 +118,7 @@ void srslte_uci_nr_free(srslte_uci_nr_t* q) SRSLTE_MEM_ZERO(q, srslte_uci_nr_t, 1); } -static int -uci_nr_sequence_generation_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) +static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) { int A = 0; @@ -124,12 +133,62 @@ uci_nr_sequence_generation_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_u return A; } -static int -uci_nr_sequence_generation(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) +static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +{ + int A = 0; + + // Append ACK bits + srslte_vec_u8_copy(value->ack, &sequence[A], cfg->o_ack); + A += cfg->o_ack; + + // Append SR bits + srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr); + A += cfg->o_sr; + + return A; +} + +static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) { // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { - return uci_nr_sequence_generation_ack_sr(cfg, value, sequence); + return cfg->o_ack + cfg->o_sr; + } + + // 6.3.1.1.2 CSI only + if (cfg->o_ack == 0 && cfg->o_sr == 0) { + ERROR("CSI only are not implemented\n"); + return SRSLTE_ERROR; + } + + // 6.3.1.1.3 HARQ-ACK/SR and CSI + ERROR("HARQ-ACK/SR and CSI encoding are not implemented\n"); + return SRSLTE_ERROR; +} + +static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) +{ + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation + if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + return uci_nr_pack_ack_sr(cfg, value, sequence); + } + + // 6.3.1.1.2 CSI only + if (cfg->o_ack == 0 && cfg->o_sr == 0) { + ERROR("CSI only are not implemented\n"); + return SRSLTE_ERROR; + } + + // 6.3.1.1.3 HARQ-ACK/SR and CSI + ERROR("HARQ-ACK/SR and CSI encoding are not implemented\n"); + return SRSLTE_ERROR; +} + +static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +{ + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation + if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + return uci_nr_unpack_ack_sr(cfg, sequence, value); } // 6.3.1.1.2 CSI only @@ -307,10 +366,40 @@ uci_nr_encode_3_11_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint3 return E; } +static int uci_nr_decode_3_11_bit(srslte_uci_nr_t* q, + const srslte_uci_cfg_nr_t* cfg, + uint32_t A, + const int8_t* llr, + uint32_t E, + bool* decoded_ok) +{ + // Check E for avoiding zero division + if (E < 1) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Compute average LLR power + float pwr = sqrtf(srslte_vec_avg_power_bf(llr, E)); + if (!isnormal(pwr)) { + return SRSLTE_ERROR; + } + + // Decode + float corr = (float)srslte_block_decode_i8(llr, E, q->bit_sequence, A); + + // Normalise correlation + corr /= sqrtf(pwr) * E; + + // Take decoded decision with threshold + *decoded_ok = (corr > UCI_NR_BLOCK_CORR_THRESHOLD); + + return SRSLTE_SUCCESS; +} + #define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN)) static int -uci_nr_encode_11_1906_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E_uci) +uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E_uci) { // If ( A ≥ 360 and E ≥ 1088 ) or if A ≥ 1013 , I seg = 1 ; otherwise I seg = 0 uint32_t I_seg = 0; @@ -342,7 +431,7 @@ uci_nr_encode_11_1906_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui for (uint32_t r = 0, s = 0; r < C; r++) { uint32_t k = 0; - // Suffix A_prime - A zeros for the first CB only + // Prefix (A_prime - A) zeros for the first CB only if (r == 0) { for (uint32_t i = 0; i < (A_prime - A); i++) { q->c[k++] = 0; @@ -372,18 +461,92 @@ uci_nr_encode_11_1906_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui return E_uci; } -int uci_nr_encode(srslte_uci_nr_t* q, - const srslte_uci_cfg_nr_t* uci_cfg, - const srslte_uci_value_nr_t* uci_value, - uint8_t* o, - uint32_t E_uci) +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, + uint32_t E_uci, + bool* decoded_ok) +{ + *decoded_ok = true; + + // If ( A ≥ 360 and E ≥ 1088 ) or if A ≥ 1013 , I seg = 1 ; otherwise I seg = 0 + uint32_t I_seg = 0; + if ((A >= 360 && E_uci >= 1088) || A >= 1013) { + I_seg = 1; + } + + // Select CRC + srslte_crc_t* crc = &q->crc6; + if (A >= 20) { + crc = &q->crc11; + } + + // Segmentation + uint32_t C = 1; + if (I_seg == 1) { + C = 2; + } + uint32_t A_prime = CEIL(A, C) * C; + + // Get polar code + uint32_t K_r = A_prime / C + crc->order; + uint32_t E_r = E_uci / C; + if (srslte_polar_code_get(&q->code, K_r, E_r, 9U) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Write codeword + for (uint32_t r = 0, s = 0; r < C; r++) { + uint32_t k = 0; + + // 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); + + // 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) < + SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // 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); + (*decoded_ok) = ((*decoded_ok) && (checksum1 == checksum2)); + + // Prefix (A_prime - A) zeros for the first CB only + if (r == 0) { + for (uint32_t i = 0; i < (A_prime - A); i++) { + k++; + } + } + + // Load codeword bits + while (k < A_prime / C) { + q->bit_sequence[s++] = q->c[k++]; + } + } + + return SRSLTE_SUCCESS; +} + +static int uci_nr_encode(srslte_uci_nr_t* q, + const srslte_uci_cfg_nr_t* uci_cfg, + const srslte_uci_value_nr_t* uci_value, + uint8_t* o, + uint32_t E_uci) { if (q == NULL || uci_cfg == NULL || uci_value == NULL || o == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } // 6.3.1.1 UCI bit sequence generation - int A = uci_nr_sequence_generation(uci_cfg, uci_value, q->bit_sequence); + int A = uci_nr_packing(uci_cfg, uci_value, q->bit_sequence); if (A < SRSLTE_SUCCESS) { ERROR("Generating bit sequence"); return SRSLTE_ERROR; @@ -400,17 +563,60 @@ int uci_nr_encode(srslte_uci_nr_t* q, } // 5.3.3.3 Encoding of other small block lengths - if (A <= 11) { + if (A <= SRSLTE_FEC_BLOCK_MAX_NOF_BITS) { return uci_nr_encode_3_11_bit(q, uci_cfg, A, o, E_uci); } + // Encoding of other sizes up to 1906 if (A < UCI_NR_MAX_A) { - return uci_nr_encode_11_1906_bit(q, uci_cfg, A, o, E_uci); + return uci_nr_encode_11_1706_bit(q, uci_cfg, A, o, E_uci); } return SRSLTE_ERROR; } +static int uci_nr_decode(srslte_uci_nr_t* q, + const srslte_uci_cfg_nr_t* uci_cfg, + const int8_t* llr, + uint32_t E_uci, + srslte_uci_value_nr_t* uci_value) +{ + if (q == NULL || uci_cfg == NULL || uci_value == NULL || llr == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // 6.3.1.1 UCI bit sequence generation + int A = uci_nr_A(uci_cfg); + if (A < SRSLTE_SUCCESS) { + ERROR("Error getting number of bits\n"); + return SRSLTE_ERROR; + } + + // Decode LLR + if (A == 1) { + ERROR("Not implemented\n"); + } else if (A == 2) { + ERROR("Not implemented\n"); + } else if (A <= 11) { + if (uci_nr_decode_3_11_bit(q, uci_cfg, A, llr, E_uci, &uci_value->valid) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + } else if (A < UCI_NR_MAX_A) { + if (uci_nr_decode_11_1706_bit(q, uci_cfg, A, llr, E_uci, &uci_value->valid) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + } else { + ERROR("Invalid number of bits (A=%d)\n", A); + } + + // Unpack bits + if (uci_nr_unpacking(uci_cfg, q->bit_sequence, uci_value) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + // Implements TS 38.212 Table 6.3.1.4-1: Total rate matching output sequence length Etot static int uci_nr_pucch_E_tot(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg) { @@ -418,8 +624,15 @@ static int uci_nr_pucch_E_tot(const srslte_pucch_nr_resource_t* pucch_cfg, const return SRSLTE_ERROR_INVALID_INPUTS; } - switch (pucch_cfg->format) { + // 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); @@ -482,3 +695,23 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q, return uci_nr_encode(q, uci_cfg, value, o, E_uci); } + +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, + srslte_uci_value_nr_t* value) +{ + + int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg); + if (E_tot < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot); + if (E_uci < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + return uci_nr_decode(q, uci_cfg, llr, E_uci, value); +} diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index e8b8841e5..494ca4beb 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -543,6 +543,28 @@ float srslte_vec_avg_power_sf(const int16_t* x, const uint32_t len) return acc; } +float srslte_vec_avg_power_bf(const int8_t* x, const uint32_t len) +{ + // Accumulator + float acc = 0.0f; + + for (uint32_t i = 0; i < len; i++) { + // Read value and typecast to float + float t = (float)x[i]; + + // Square value + acc += t * t; + } + + // Do average + if (len) { + acc /= len; + } + + // Return accumulated value + return acc; +} + // Correlation assumes zero-mean x and y float srslte_vec_corr_ccc(const cf_t* x, cf_t* y, const uint32_t len) {