mirror of https://github.com/PentHertz/srsLTE.git
Implement NR-PUCCH Format 2 encode/decode. Initial NR-PUCCH procedures.
This commit is contained in:
parent
4b6849b775
commit
958afaee60
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -17,6 +17,54 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef SRSLTE_UCI_CFG_NR_H
|
||||
#define SRSLTE_UCI_CFG_NR_H
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue