SRSUE: Initial NR-PUCCH HARQ feedback

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent ff5fbbf0a0
commit d807ccc3dd

@ -108,6 +108,11 @@ extern "C" {
*/
#define SRSLTE_MAX_NOF_DL_ALLOCATION 16
/**
* @brief Maximum dl-DataToUL-ACK value. This is defined by TS 38.331 v15.10.1 in PUCCH-Config
*/
#define SRSLTE_MAX_NOF_DL_DATA_TO_UL 8
typedef enum SRSLTE_API {
srslte_coreset_mapping_type_non_interleaved = 0,
srslte_coreset_mapping_type_interleaved,
@ -210,6 +215,15 @@ typedef enum SRSLTE_API {
srslte_xoverhead_18
} srslte_xoverhead_t;
/**
* @brief PDSCH HARQ ACK codebook configuration
* @remark Described in TS 38.331 V15.10.0 PhysicalCellGroupConfig
*/
typedef enum SRSLTE_API {
srslte_pdsch_harq_ack_codebook_none = 0,
srslte_pdsch_harq_ack_codebook_semi_static,
srslte_pdsch_harq_ack_codebook_dynamic,
} srslte_pdsch_harq_ack_codebook_t;
/**
* @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
*/
@ -281,6 +295,8 @@ typedef struct SRSLTE_API {
uint32_t id;
uint32_t coreset_id;
uint32_t duration; // in slots
uint32_t periodicity;
uint32_t offset;
srslte_search_space_type_t type;
uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR];
} srslte_search_space_t;

@ -67,6 +67,21 @@
*/
#define SRSLTE_PUCCH_NR_MAX_CODE_RATE 7
/**
* Maximum number of NR-PUCCH resources per set (TS 38.331 maxNrofPUCCH-ResourcesPerSet)
*/
#define SRSLTE_PUCCH_NR_MAX_NOF_RESOURCES_PER_SET 32
/**
* Maximum number NR-PUCCH resource sets (TS 38.331 maxNrofPUCCH-ResourceSets)
*/
#define SRSLTE_PUCCH_NR_MAX_NOF_SETS 4
/**
* Maximum numer of NR-PUCCH CS indexes (TS 38.213 Table 9.2.1-1: PUCCH resource sets...)
*/
#define SRSLTE_PUCCH_NR_MAX_NOF_CS_INDEXES 4
typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_FORMAT_0 = 0,
SRSLTE_PUCCH_NR_FORMAT_1,
@ -126,6 +141,18 @@ typedef struct SRSLTE_API {
bool additional_dmrs; ///< UE enables 2 DMRS symbols per hop of a PUCCH Format 3 or 4
} srslte_pucch_nr_resource_t;
typedef struct SRSLTE_API {
srslte_pucch_nr_resource_t resources[SRSLTE_PUCCH_NR_MAX_NOF_RESOURCES_PER_SET];
uint32_t nof_resources; ///< Set to 0 if it is NOT provided by higher layers
uint32_t max_payload_size; ///< Maximum payload size, set to 0 if not present
} srslte_pucch_nr_resource_set_t;
typedef struct SRSLTE_API {
srslte_pucch_nr_common_cfg_t common; ///< NR-PUCCH configuration common for all formats and resources
srslte_pucch_nr_resource_set_t sets[SRSLTE_PUCCH_NR_MAX_NOF_SETS]; ///< Resource sets, indexed by pucch-ResourceSetId
bool enabled; ///< Set to true if any set is enabled
} srslte_pucch_nr_hl_cfg_t;
/**
* @brief Validates an NR-PUCCH resource configuration provided by upper layers
* @param resource Resource configuration to validate

@ -241,4 +241,9 @@ SRSLTE_API int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t*
cf_t* slot_symbols,
srslte_uci_value_nr_t* uci_value);
SRSLTE_API uint32_t srslte_pucch_nr_tx_info(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len);
#endif // SRSLTE_PUCCH_NR_H

@ -99,4 +99,15 @@ SRSLTE_API int srslte_ra_ul_nr_freq(const srslte_carrier_nr_t* carrier,
const srslte_dci_ul_nr_t* dci_ul,
srslte_sch_grant_nr_t* grant);
/**
* @brief Selects a valid PUCCH resource for transmission
* @param pucch_cfg PUCCH configuration from upper layers
* @param uci_cfg Uplink Control information configuration (and PDCCH context)
* @param[out] resource Selected resource for transmitting PUCCH
* @return SRSLTE_SUCCESS if provided configuration is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
srslte_pucch_nr_resource_t* resource);
#endif // SRSLTE_RA_UL_NR_H

@ -17,6 +17,12 @@
#include <stdbool.h>
#include <stdint.h>
/**
* @brief Maximum number of Uplink Control Bits
* @remark TS 38.212 section 5.2.1 Polar coding: The value of A is no larger than 1706.
*/
#define SRSLTE_UCI_NR_MAX_NOF_BITS 1706U
/**
* @brief Maximum number of HARQ ACK feedback bits that can be carried in Uplink Control Information (UCI) message
*/
@ -43,12 +49,15 @@
* @brief Uplink Control Information (UCI) message configuration
*/
typedef struct SRSLTE_API {
uint32_t o_ack; ///< Number of HARQ-ACK bits
uint32_t o_sr; ///< Number of SR bits
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 (PUSCH only)
uint16_t rnti; ///< RNTI
uint32_t o_ack; ///< Number of HARQ-ACK bits
uint32_t o_sr; ///< Number of SR bits
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 (PUSCH only)
uint16_t rnti; ///< RNTI
uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1
uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception
uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or DCI format 1_1
} srslte_uci_cfg_nr_t;
/**
@ -62,4 +71,12 @@ typedef struct SRSLTE_API {
bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter
} srslte_uci_value_nr_t;
/**
* @brief Uplink Control Information (UCI) data (configuration + values)
*/
typedef struct SRSLTE_API {
srslte_uci_cfg_nr_t cfg;
srslte_uci_value_nr_t value;
} srslte_uci_data_nr_t;
#endif // SRSLTE_UCI_CFG_NR_H

@ -114,4 +114,15 @@ SRSLTE_API int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
int8_t* llr,
srslte_uci_value_nr_t* value);
SRSLTE_API uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg);
/**
* @brief Converts to string an UCI data structure
* @param uci_data UCO data structure
* @param str Destination string
* @param str_len String length
* @return Resultant string length
*/
SRSLTE_API uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len);
#endif // SRSLTE_UCI_NR_H

@ -19,6 +19,7 @@
#include "srslte/phy/phch/dci_nr.h"
#include "srslte/phy/phch/pdcch_nr.h"
#include "srslte/phy/phch/pdsch_nr.h"
#include <srslte/phy/phch/uci_cfg_nr.h>
/**
* Maximum number of CORESET
@ -59,13 +60,16 @@ typedef struct SRSLTE_API {
} srslte_ue_dl_nr_pdcch_cfg_t;
typedef struct {
uint32_t v_dai_dl;
bool dci_format_1_1;
uint32_t scell_idx; ///< Serving cell index
uint32_t v_dai_dl; ///< Downlink Assigment Index
bool dci_format_1_1; ///< Set to true if the PDSCH transmission is triggered by a PDCCH DCI format 1_1 transmission
uint32_t k1; ///< HARQ feedback timing
uint16_t rnti;
uint32_t pucch_resource_id;
} srslte_pdsch_ack_resource_nr_t;
typedef struct {
srslte_pdsch_ack_resource_nr_t resource;
uint32_t k;
uint8_t value[SRSLTE_MAX_CODEWORDS]; // 0/1 or 2 for DTX
bool present; // set to true if there is a PDSCH on serving cell c associated with PDCCH in PDCCH monitoring occasion
// m, or there is a PDCCH indicating SPS PDSCH release on serving cell c
@ -89,10 +93,13 @@ typedef struct {
} srslte_pdsch_ack_nr_t;
typedef struct SRSLTE_API {
bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided
bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided
bool pdsch_harq_ack_codebook_semi_static; ///< set to true for pdsch-HARQ-ACK-Codebook is set to semi-static
bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided
bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided
srslte_pdsch_harq_ack_codebook_t pdsch_harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration
bool max_cw_sched_dci_is_2; ///< Param maxNrofCodeWordsScheduledByDCI, set to true if present and equal to 2
uint32_t dl_data_to_ul_ack[SRSLTE_MAX_NOF_DL_DATA_TO_UL];
uint32_t nof_dl_data_to_ul_ack;
} srslte_ue_dl_nr_harq_ack_cfg_t;
typedef struct SRSLTE_API {
@ -153,8 +160,12 @@ SRSLTE_API int srslte_ue_dl_nr_pdsch_info(const srslte_ue_dl_nr_t* q,
char* str,
uint32_t str_len);
SRSLTE_API int srslte_ue_dl_nr_pdsch_ack_resource(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
const srslte_dci_dl_nr_t* dci_dl,
srslte_pdsch_ack_resource_nr_t* pdsch_ack_resource);
SRSLTE_API int srslte_ue_dl_nr_gen_ack(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
const srslte_pdsch_ack_nr_t* ack_info,
uint8_t* uci_data);
srslte_uci_data_nr_t* uci_data);
#endif // SRSLTE_UE_DL_NR_H

@ -27,10 +27,13 @@
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/dft/ofdm.h"
#include "srslte/phy/phch/phch_cfg_nr.h"
#include "srslte/phy/phch/pucch_cfg_nr.h"
#include "srslte/phy/phch/pucch_nr.h"
#include "srslte/phy/phch/pusch_nr.h"
typedef struct SRSLTE_API {
srslte_pusch_nr_args_t pusch;
srslte_pucch_nr_args_t pucch;
uint32_t nof_max_prb;
} srslte_ue_ul_nr_args_t;
@ -43,8 +46,8 @@ typedef struct SRSLTE_API {
cf_t* sf_symbols[SRSLTE_MAX_PORTS];
srslte_pusch_nr_t pusch;
srslte_pucch_nr_t pucch;
srslte_dmrs_sch_t dmrs;
} srslte_ue_ul_nr_t;
SRSLTE_API int srslte_ue_ul_nr_init(srslte_ue_ul_nr_t* q, cf_t* output, const srslte_ue_ul_nr_args_t* args);
@ -56,9 +59,20 @@ SRSLTE_API int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q,
const srslte_sch_cfg_nr_t* pusch_cfg,
uint8_t* data_);
SRSLTE_API int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot_cfg,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data);
SRSLTE_API void srslte_ue_ul_nr_free(srslte_ue_ul_nr_t* q);
SRSLTE_API int
srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, const srslte_sch_cfg_nr_t* cfg, char* str, uint32_t str_len);
SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len);
#endif // SRSLTE_UE_UL_DATA_H

@ -98,9 +98,11 @@ extern "C" {
#include "srslte/phy/phch/ra_dl_nr.h"
#include "srslte/phy/phch/ra_nr.h"
#include "srslte/phy/phch/ra_ul.h"
#include "srslte/phy/phch/ra_ul_nr.h"
#include "srslte/phy/phch/regs.h"
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/phch/uci.h"
#include "srslte/phy/phch/uci_nr.h"
#include "srslte/phy/ue/ue_cell_search.h"
#include "srslte/phy/ue/ue_dl.h"

@ -707,4 +707,58 @@ int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
}
return SRSLTE_SUCCESS;
}
}
static uint32_t pucch_nr_resource_info(const srslte_pucch_nr_resource_t* r, char* str, uint32_t str_len)
{
uint32_t len = 0;
uint32_t nof_prb = 1;
if (r->format == SRSLTE_PUCCH_NR_FORMAT_2 || r->format == SRSLTE_PUCCH_NR_FORMAT_3) {
nof_prb = r->nof_prb;
}
len = srslte_print_check(str,
str_len,
len,
"f=%d, prb=%d:%d, symb=%d:%d",
(int)r->format,
r->starting_prb,
nof_prb,
r->start_symbol_idx,
r->nof_symbols);
if (r->intra_slot_hopping) {
len = srslte_print_check(str, str_len, len, ", hop=%d", r->second_hop_prb);
}
if (r->format == SRSLTE_PUCCH_NR_FORMAT_0 || r->format == SRSLTE_PUCCH_NR_FORMAT_1) {
len = srslte_print_check(str, str_len, len, ", cs=%d", r->initial_cyclic_shift);
}
if (r->format == SRSLTE_PUCCH_NR_FORMAT_1) {
len = srslte_print_check(str, str_len, len, ", occ=%d", r->time_domain_occ);
}
if (r->format == SRSLTE_PUCCH_NR_FORMAT_4) {
len = srslte_print_check(str, str_len, len, ", occ=%d:%d", r->occ_index, r->occ_lenth);
}
return len;
}
uint32_t srslte_pucch_nr_tx_info(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
len += pucch_nr_resource_info(resource, &str[len], str_len - len);
len = srslte_print_check(str, str_len, len, ", ");
len += srslte_uci_nr_info(uci_data, &str[len], str_len - len);
return len;
}

@ -395,3 +395,69 @@ int srslte_ra_ul_nr_freq(const srslte_carrier_nr_t* carrier,
ERROR("Only DCI Format 0_0 is supported");
return SRSLTE_ERROR;
}
// Implements TS 38.213 Table 9.2.1-1: PUCCH resource sets before dedicated PUCCH resource configuration
static int ra_ul_nr_pucch_resource_default(uint32_t r_pucch, srslte_pucch_nr_resource_t* resource)
{
ERROR("Not implemented");
return SRSLTE_ERROR;
}
static int ra_ul_nr_pucch_resource_hl(const srslte_pucch_nr_hl_cfg_t* cfg,
uint32_t O_uci,
uint32_t pucch_resource_id,
srslte_pucch_nr_resource_t* resource)
{
uint32_t N2 = cfg->sets[1].max_payload_size > 0 ? cfg->sets[1].max_payload_size : SRSLTE_UCI_NR_MAX_NOF_BITS;
uint32_t N3 = cfg->sets[2].max_payload_size > 0 ? cfg->sets[2].max_payload_size : SRSLTE_UCI_NR_MAX_NOF_BITS;
// If the UE transmits O UCI UCI information bits, that include HARQ-ACK information bits, the UE determines a PUCCH
// resource set to be...
uint32_t resource_set_id = 3;
if (O_uci <= 2 && cfg->sets[0].nof_resources > 0) {
resource_set_id = 0;
} else if (O_uci <= N2 && cfg->sets[1].nof_resources > 0) {
resource_set_id = 1;
} else if (O_uci <= N3 && cfg->sets[2].nof_resources > 0) {
resource_set_id = 2;
} else if (cfg->sets[3].nof_resources == 0) {
ERROR("Invalid PUCCH resource configuration, N3=%d, O_uci=%d", N3, O_uci);
return SRSLTE_ERROR;
} else if (O_uci > SRSLTE_UCI_NR_MAX_NOF_BITS) {
ERROR("The number of UCI bits (%d), exceeds the maximum (%d)", O_uci, SRSLTE_UCI_NR_MAX_NOF_BITS);
return SRSLTE_ERROR;
}
// Select resource from the set
if (pucch_resource_id >= SRSLTE_PUCCH_NR_MAX_NOF_RESOURCES_PER_SET ||
pucch_resource_id >= cfg->sets[resource_set_id].nof_resources) {
ERROR("The PUCCH resource identifier (%d) exceeds the number of configured resources (%d) for set identifier %d",
pucch_resource_id,
cfg->sets[resource_set_id].nof_resources,
resource_set_id);
return SRSLTE_ERROR;
}
*resource = cfg->sets[resource_set_id].resources[pucch_resource_id];
return SRSLTE_SUCCESS;
}
int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
srslte_pucch_nr_resource_t* resource)
{
if (pucch_cfg == NULL || uci_cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
uint32_t O_uci = srslte_uci_nr_total_bits(uci_cfg);
// If a UE does not have dedicated PUCCH resource configuration, provided by PUCCH-ResourceSet in PUCCH-Config,
// a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size
// transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs.
if (!pucch_cfg->enabled) {
uint32_t r_pucch = (2 * uci_cfg->n_cce_0) + 2 * uci_cfg->pucch_resource_id;
return ra_ul_nr_pucch_resource_default(r_pucch, resource);
}
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource);
}

@ -706,10 +706,10 @@ int srslte_sch_nr_tb_info(const srslte_sch_tb_t* tb, char* str, uint32_t str_len
len += srslte_print_check(str,
str_len,
len,
"tb={mod=%s,Nl=%d,TBS=%d,R=%.3f,rv=%d,Nre=%d,Nbit=%d,cw=%d}",
"tb={mod=%s,Nl=%d,tbs=%d,R=%.3f,rv=%d,Nre=%d,Nbit=%d,cw=%d}",
srslte_mod_string(tb->mod),
tb->N_L,
tb->tbs,
tb->tbs / 8,
tb->R,
tb->rv,
tb->nof_re,

@ -20,8 +20,6 @@
#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
@ -84,14 +82,14 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args)
}
// Allocate bit sequence with space for the CRC
q->bit_sequence = srslte_vec_u8_malloc(UCI_NR_MAX_A);
q->bit_sequence = srslte_vec_u8_malloc(SRSLTE_UCI_NR_MAX_NOF_BITS);
if (q->bit_sequence == NULL) {
ERROR("Error malloc");
return SRSLTE_ERROR;
}
// Allocate c with space for a and the CRC
q->c = srslte_vec_u8_malloc(UCI_NR_MAX_A + UCI_NR_MAX_L);
q->c = srslte_vec_u8_malloc(SRSLTE_UCI_NR_MAX_NOF_BITS + UCI_NR_MAX_L);
if (q->c == NULL) {
ERROR("Error malloc");
return SRSLTE_ERROR;
@ -656,7 +654,7 @@ static int uci_nr_encode(srslte_uci_nr_t* q,
}
// Encoding of other sizes up to 1906
if (A < UCI_NR_MAX_A) {
if (A < SRSLTE_UCI_NR_MAX_NOF_BITS) {
return uci_nr_encode_11_1706_bit(q, uci_cfg, A, o, E_uci);
}
@ -689,7 +687,7 @@ static int uci_nr_decode(srslte_uci_nr_t* q,
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) {
} else if (A < SRSLTE_UCI_NR_MAX_NOF_BITS) {
if (uci_nr_decode_11_1706_bit(q, uci_cfg, A, llr, E_uci, &uci_value->valid) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
@ -785,3 +783,45 @@ int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
return uci_nr_decode(q, uci_cfg, llr, E_uci, value);
}
uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg)
{
if (uci_cfg == NULL) {
return 0;
}
return uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2 + uci_cfg->o_sr;
}
uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len)
{
uint32_t len = 0;
len = srslte_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.rnti);
if (uci_data->cfg.o_ack > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.ack, uci_data->cfg.o_ack);
len = srslte_print_check(str, str_len, len, ", ack=%s", str2);
}
if (uci_data->cfg.o_csi1 > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.csi1, uci_data->cfg.o_csi1);
len = srslte_print_check(str, str_len, len, ", csi1=%s", str2);
}
if (uci_data->cfg.o_csi2 > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.csi2, uci_data->cfg.o_csi2);
len = srslte_print_check(str, str_len, len, ", csi2=%s", str2);
}
if (uci_data->cfg.o_sr > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.sr, uci_data->cfg.o_sr);
len = srslte_print_check(str, str_len, len, ", sr=%s", str2);
}
return len;
}

@ -517,11 +517,13 @@ static uint32_t ue_dl_nr_V_DL_DAI(uint32_t dai)
return dai + 1;
}
static int
ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, const srslte_pdsch_ack_nr_t* ack_info, uint8_t* o_ack)
static int ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
const srslte_pdsch_ack_nr_t* ack_info,
srslte_uci_data_nr_t* uci_data)
{
bool harq_ack_spatial_bundling =
ack_info->use_pusch ? cfg->harq_ack_spatial_bundling_pusch : cfg->harq_ack_spatial_bundling_pucch;
uint8_t* o_ack = uci_data->value.ack;
uint32_t m = 0; // PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion index: lower index corresponds to
// earlier PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion
@ -529,11 +531,10 @@ ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, const srslte_p
uint32_t V_temp = 0;
uint32_t V_temp2 = 0;
uint32_t N_DL_cells = ack_info->nof_cc; // number of serving cells configured by higher layers for the UE
uint32_t M = ack_info->cc[0].M; // Set M to the number of PDCCH monitoring occasion(s)
uint32_t N_DL_cells = ack_info->nof_cc; // number of serving cells configured by higher layers for the UE
// The following code follows the exact pseudo-code provided in TS 38.213 9.1.3.1 Type-2 HARQ-ACK codebook ...
while (m < M) {
while (m < SRSLTE_UCI_NR_MAX_M) {
uint32_t c = 0; // serving cell index: lower indexes correspond to lower RRC indexes of corresponding cell
while (c < N_DL_cells) {
// Get ACK information of serving cell c for the PDCH monitoring occasion m
@ -563,6 +564,10 @@ ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, const srslte_p
c = c + 1;
} else {
if (ack->present) {
// Load ACK resource data into UCI info
uci_data->cfg.pucch_resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id;
uci_data->cfg.rnti = ack_info->cc[c].m[m].resource.rnti;
if (V_DL_CDAI <= V_temp) {
j = j + 1;
}
@ -605,20 +610,63 @@ ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, const srslte_p
// if harq-ACK-SpatialBundlingPUCCH is not provided to the UE and the UE is configured by
// maxNrofCodeWordsScheduledByDCI with reception of two transport blocks for at least one configured DL BWP of a
// serving cell,
uint32_t O_ack = 4 * j + V_temp2;
if (!harq_ack_spatial_bundling && cfg->max_cw_sched_dci_is_2) {
O_ack = 2 * (4 * j + V_temp2);
uci_data->cfg.o_ack = 2 * (4 * j + V_temp2);
} else {
uci_data->cfg.o_ack = 4 * j + V_temp2;
}
// Implement here SPS PDSCH reception
// ...
return (int)O_ack;
return SRSLTE_SUCCESS;
}
int ue_dl_nr_pdsch_k1(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg, const srslte_dci_dl_nr_t* dci_dl)
{
// For DCI format 1_0, the PDSCH-to-HARQ_feedback timing indicator field values map to {1, 2, 3, 4, 5, 6, 7, 8}
if (dci_dl->format == srslte_dci_format_nr_1_0) {
return (int)dci_dl->harq_feedback + 1;
}
// For DCI format 1_1, if present, the PDSCH-to-HARQ_feedback timing indicator field values map to values for a set of
// number of slots provided by dl-DataToUL-ACK as defined in Table 9.2.3-1.
if (dci_dl->harq_feedback >= SRSLTE_MAX_NOF_DL_DATA_TO_UL || dci_dl->harq_feedback >= cfg->nof_dl_data_to_ul_ack) {
ERROR("Out-of-range PDSCH-to-HARQ feedback index (%d, max %d)", dci_dl->harq_feedback, cfg->nof_dl_data_to_ul_ack);
return SRSLTE_ERROR;
}
return cfg->dl_data_to_ul_ack[dci_dl->harq_feedback];
}
int srslte_ue_dl_nr_pdsch_ack_resource(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
const srslte_dci_dl_nr_t* dci_dl,
srslte_pdsch_ack_resource_nr_t* pdsch_ack_resource)
{
if (cfg == NULL || dci_dl == NULL || pdsch_ack_resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Calculate Data to UL ACK timing k1
int k1 = ue_dl_nr_pdsch_k1(cfg, dci_dl);
if (k1 < SRSLTE_ERROR) {
ERROR("Error calculating K1");
return SRSLTE_ERROR;
}
// Fill PDSCH resource
pdsch_ack_resource->dci_format_1_1 = (dci_dl->format == srslte_dci_format_nr_1_1);
pdsch_ack_resource->k1 = k1;
pdsch_ack_resource->v_dai_dl = dci_dl->dai;
pdsch_ack_resource->rnti = dci_dl->rnti;
pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource;
return SRSLTE_SUCCESS;
}
int srslte_ue_dl_nr_gen_ack(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
const srslte_pdsch_ack_nr_t* ack_info,
uint8_t* uci_data)
srslte_uci_data_nr_t* uci_data)
{
// Check inputs
if (cfg == NULL || ack_info == NULL || uci_data == NULL) {
@ -626,7 +674,7 @@ int srslte_ue_dl_nr_gen_ack(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
}
// According TS 38.213 9.1.2 Type-1 HARQ-ACK codebook determination
if (cfg->pdsch_harq_ack_codebook_semi_static) {
if (cfg->pdsch_harq_ack_codebook == srslte_pdsch_harq_ack_codebook_semi_static) {
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = semi-static.
ERROR("Type-1 HARQ-ACK codebook determination is NOT implemented");
return SRSLTE_ERROR;
@ -634,5 +682,10 @@ int srslte_ue_dl_nr_gen_ack(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
// According TS 38.213 9.1.3 Type-2 HARQ-ACK codebook determination
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = dynamic.
return ue_dl_nr_gen_ack_type2(cfg, ack_info, uci_data);
if (cfg->pdsch_harq_ack_codebook == srslte_pdsch_harq_ack_codebook_dynamic) {
return ue_dl_nr_gen_ack_type2(cfg, ack_info, uci_data);
}
ERROR("No HARQ-ACK codebook determination is NOT implemented");
return SRSLTE_ERROR;
}

@ -51,6 +51,11 @@ int srslte_ue_ul_nr_init(srslte_ue_ul_nr_t* q, cf_t* output, const srslte_ue_ul_
return SRSLTE_ERROR;
}
if (srslte_pucch_nr_init(&q->pucch, &args->pucch) < SRSLTE_SUCCESS) {
ERROR("Error UCI\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
@ -126,6 +131,58 @@ int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q,
return SRSLTE_SUCCESS;
}
static int ue_ul_nr_encode_pucch_format0(srslte_ue_ul_nr_t* q,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data)
{
ERROR("Not implemented");
return SRSLTE_ERROR;
}
static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data)
{
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
b[0] = uci_data->value.ack[0];
uint32_t nof_bits = 1;
return srslte_pucch_nr_format1_encode(&q->pucch, &q->carrier, cfg, slot, resource, b, nof_bits, q->sf_symbols[0]);
}
int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot_cfg,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data)
{
// Check inputs
if (q == NULL || slot_cfg == NULL || resource == NULL || uci_data == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Actual PUCCH encoding
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_0:
return ue_ul_nr_encode_pucch_format0(q, resource, uci_data);
case SRSLTE_PUCCH_NR_FORMAT_1:
return ue_ul_nr_encode_pucch_format1(q, slot_cfg, cfg, resource, uci_data);
case SRSLTE_PUCCH_NR_FORMAT_2:
case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4:
return srslte_pucch_nr_format_2_3_4_encode(
&q->pucch, &q->carrier, cfg, slot_cfg, resource, &uci_data->cfg, &uci_data->value, q->sf_symbols[0]);
case SRSLTE_PUCCH_NR_FORMAT_ERROR:
default:
ERROR("Invalid case");
break;
}
return SRSLTE_ERROR;
}
void srslte_ue_ul_nr_free(srslte_ue_ul_nr_t* q)
{
if (q == NULL) {
@ -137,6 +194,8 @@ void srslte_ue_ul_nr_free(srslte_ue_ul_nr_t* q)
}
srslte_pusch_nr_free(&q->pusch);
srslte_dmrs_sch_free(&q->dmrs);
SRSLTE_MEM_ZERO(q, srslte_ue_ul_nr_t, 1);
}
int srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, const srslte_sch_cfg_nr_t* cfg, char* str, uint32_t str_len)
@ -146,5 +205,18 @@ int srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, const srslte_sch_cfg_
// Append PDSCH info
len += srslte_pusch_nr_tx_info(&q->pusch, cfg, &cfg->grant, &str[len], str_len - len);
return len;
}
int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len)
{
int len = 0;
// Append PDSCH info
len += srslte_pucch_nr_tx_info(resource, uci_data, &str[len], str_len - len);
return len;
}

@ -54,6 +54,10 @@ private:
srslte_softbuffer_tx_t softbuffer_tx = {};
srslte_softbuffer_rx_t softbuffer_rx = {};
std::vector<uint8_t> tx_data;
// Methods for DL...
void decode_pdcch_ul();
void decode_pdcch_dl();
};
} // namespace nr

@ -33,6 +33,7 @@ typedef struct {
typedef struct {
srslte_sch_hl_cfg_nr_t pdsch;
srslte_sch_hl_cfg_nr_t pusch;
srslte_pucch_nr_hl_cfg_t pucch;
srslte_prach_cfg_t prach;
srslte_ue_dl_nr_pdcch_cfg_t pdcch;
srslte_ue_dl_nr_harq_ack_cfg_t harq_ack;
@ -41,13 +42,25 @@ typedef struct {
class state
{
private:
struct pending_grant_t {
struct pending_ul_grant_t {
bool enable;
uint32_t pid;
srslte_sch_cfg_nr_t sch_cfg;
};
srslte::circular_array<pending_grant_t, TTIMOD_SZ> pending_ul_grant = {};
mutable std::mutex pending_ul_grant_mutex;
srslte::circular_array<pending_ul_grant_t, TTIMOD_SZ> pending_ul_grant = {};
mutable std::mutex pending_ul_grant_mutex;
struct pending_dl_grant_t {
bool enable;
uint32_t pid;
srslte_sch_cfg_nr_t sch_cfg;
srslte_pdsch_ack_resource_nr_t ack_resource;
};
srslte::circular_array<pending_dl_grant_t, TTIMOD_SZ> pending_dl_grant = {};
mutable std::mutex pending_dl_grant_mutex;
srslte::circular_array<srslte_pdsch_ack_nr_t, TTIMOD_SZ> pending_ack = {};
mutable std::mutex pending_ack_mutex;
public:
mac_interface_phy_nr* stack = nullptr;
@ -87,7 +100,7 @@ public:
// physicalCellGroupConfig
// pdsch-HARQ-ACK-Codebook: dynamic (1)
cfg.harq_ack.pdsch_harq_ack_codebook_semi_static = false;
cfg.harq_ack.pdsch_harq_ack_codebook = srslte_pdsch_harq_ack_codebook_dynamic;
// commonControlResourceSet
// controlResourceSetId: 1
@ -222,6 +235,377 @@ public:
// betaOffsetCSI-Part2-Index1: 6
// betaOffsetCSI-Part2-Index2: 6
// scaling: f1 (3)
// pucch-Config: setup (1)
// setup
// resourceSetToAddModList: 2 items
cfg.pucch.enabled = true;
// Item 0
// PUCCH-ResourceSet
// pucch-ResourceSetId: 0
// resourceList: 8 items
// Item 0
// PUCCH-ResourceId: 0
// Item 1
// PUCCH-ResourceId: 1
// Item 2
// PUCCH-ResourceId: 2
// Item 3
// PUCCH-ResourceId: 3
// Item 4
// PUCCH-ResourceId: 4
// Item 5
// PUCCH-ResourceId: 5
// Item 6
// PUCCH-ResourceId: 6
// Item 7
// PUCCH-ResourceId: 7
cfg.pucch.sets[0].nof_resources = 8;
// Item 1
// PUCCH-ResourceSet
// pucch-ResourceSetId: 1
// resourceList: 8 items
// Item 0
// PUCCH-ResourceId: 8
// Item 1
// PUCCH-ResourceId: 9
// Item 2
// PUCCH-ResourceId: 10
// Item 3
// PUCCH-ResourceId: 11
// Item 4
// PUCCH-ResourceId: 12
// Item 5
// PUCCH-ResourceId: 13
// Item 6
// PUCCH-ResourceId: 14
// Item 7
// PUCCH-ResourceId: 15
cfg.pucch.sets[1].nof_resources = 8;
// resourceToAddModList: 18 items
// Item 0
// PUCCH-Resource
// pucch-ResourceId: 0
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 0
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 0
cfg.pucch.sets[0].resources[0].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[0].starting_prb = 0;
cfg.pucch.sets[0].resources[0].initial_cyclic_shift = 0;
cfg.pucch.sets[0].resources[0].nof_symbols = 14;
cfg.pucch.sets[0].resources[0].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[0].time_domain_occ = 0;
// Item 1
// PUCCH-Resource
// pucch-ResourceId: 1
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 4
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 0
cfg.pucch.sets[0].resources[1].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[1].starting_prb = 0;
cfg.pucch.sets[0].resources[1].initial_cyclic_shift = 4;
cfg.pucch.sets[0].resources[1].nof_symbols = 14;
cfg.pucch.sets[0].resources[1].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[1].time_domain_occ = 0;
// Item 2
// PUCCH-Resource
// pucch-ResourceId: 2
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 8
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 0
cfg.pucch.sets[0].resources[2].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[2].starting_prb = 0;
cfg.pucch.sets[0].resources[2].initial_cyclic_shift = 8;
cfg.pucch.sets[0].resources[2].nof_symbols = 14;
cfg.pucch.sets[0].resources[2].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[2].time_domain_occ = 0;
// Item 3
// PUCCH-Resource
// pucch-ResourceId: 3
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 0
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 1
cfg.pucch.sets[0].resources[3].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[3].starting_prb = 0;
cfg.pucch.sets[0].resources[3].initial_cyclic_shift = 0;
cfg.pucch.sets[0].resources[3].nof_symbols = 14;
cfg.pucch.sets[0].resources[3].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[3].time_domain_occ = 1;
// Item 4
// PUCCH-Resource
// pucch-ResourceId: 4
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 4
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 1
cfg.pucch.sets[0].resources[4].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[4].starting_prb = 0;
cfg.pucch.sets[0].resources[4].initial_cyclic_shift = 4;
cfg.pucch.sets[0].resources[4].nof_symbols = 14;
cfg.pucch.sets[0].resources[4].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[4].time_domain_occ = 1;
// Item 5
// PUCCH-Resource
// pucch-ResourceId: 5
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 8
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 1
cfg.pucch.sets[0].resources[5].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[5].starting_prb = 0;
cfg.pucch.sets[0].resources[5].initial_cyclic_shift = 8;
cfg.pucch.sets[0].resources[5].nof_symbols = 14;
cfg.pucch.sets[0].resources[5].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[5].time_domain_occ = 1;
// Item 6
// PUCCH-Resource
// pucch-ResourceId: 6
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 0
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 2
cfg.pucch.sets[0].resources[6].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[6].starting_prb = 0;
cfg.pucch.sets[0].resources[6].initial_cyclic_shift = 0;
cfg.pucch.sets[0].resources[6].nof_symbols = 14;
cfg.pucch.sets[0].resources[6].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[6].time_domain_occ = 2;
// Item 7
// PUCCH-Resource
// pucch-ResourceId: 7
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 4
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 2
cfg.pucch.sets[0].resources[7].format = SRSLTE_PUCCH_NR_FORMAT_1;
cfg.pucch.sets[0].resources[7].starting_prb = 0;
cfg.pucch.sets[0].resources[7].initial_cyclic_shift = 0;
cfg.pucch.sets[0].resources[7].nof_symbols = 14;
cfg.pucch.sets[0].resources[7].start_symbol_idx = 0;
cfg.pucch.sets[0].resources[7].time_domain_occ = 2;
// Item 8
// PUCCH-Resource
// pucch-ResourceId: 8
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 0
cfg.pucch.sets[1].resources[0].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[0].starting_prb = 51;
cfg.pucch.sets[1].resources[0].nof_prb = 1;
cfg.pucch.sets[1].resources[0].nof_symbols = 2;
cfg.pucch.sets[1].resources[0].start_symbol_idx = 0;
// Item 9
// PUCCH-Resource
// pucch-ResourceId: 9
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 2
cfg.pucch.sets[1].resources[1].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[1].starting_prb = 51;
cfg.pucch.sets[1].resources[1].nof_prb = 1;
cfg.pucch.sets[1].resources[1].nof_symbols = 2;
cfg.pucch.sets[1].resources[1].start_symbol_idx = 2;
// Item 10
// PUCCH-Resource
// pucch-ResourceId: 10
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 4
cfg.pucch.sets[1].resources[2].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[2].starting_prb = 51;
cfg.pucch.sets[1].resources[2].nof_prb = 1;
cfg.pucch.sets[1].resources[2].nof_symbols = 2;
cfg.pucch.sets[1].resources[2].start_symbol_idx = 4;
// Item 11
// PUCCH-Resource
// pucch-ResourceId: 11
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 6
cfg.pucch.sets[1].resources[3].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[3].starting_prb = 51;
cfg.pucch.sets[1].resources[3].nof_prb = 1;
cfg.pucch.sets[1].resources[3].nof_symbols = 2;
cfg.pucch.sets[1].resources[3].start_symbol_idx = 6;
// Item 12
// PUCCH-Resource
// pucch-ResourceId: 12
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 8
cfg.pucch.sets[1].resources[4].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[4].starting_prb = 51;
cfg.pucch.sets[1].resources[4].nof_prb = 1;
cfg.pucch.sets[1].resources[4].nof_symbols = 2;
cfg.pucch.sets[1].resources[4].start_symbol_idx = 8;
// Item 13
// PUCCH-Resource
// pucch-ResourceId: 13
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 10
cfg.pucch.sets[1].resources[5].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[5].starting_prb = 51;
cfg.pucch.sets[1].resources[5].nof_prb = 1;
cfg.pucch.sets[1].resources[5].nof_symbols = 2;
cfg.pucch.sets[1].resources[5].start_symbol_idx = 10;
// Item 14
// PUCCH-Resource
// pucch-ResourceId: 14
// startingPRB: 51
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 12
cfg.pucch.sets[1].resources[6].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[6].starting_prb = 51;
cfg.pucch.sets[1].resources[6].nof_prb = 1;
cfg.pucch.sets[1].resources[6].nof_symbols = 2;
cfg.pucch.sets[1].resources[6].start_symbol_idx = 12;
// Item 15
// PUCCH-Resource
// pucch-ResourceId: 15
// startingPRB: 1
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 0
cfg.pucch.sets[1].resources[7].format = SRSLTE_PUCCH_NR_FORMAT_2;
cfg.pucch.sets[1].resources[7].starting_prb = 51;
cfg.pucch.sets[1].resources[7].nof_prb = 1;
cfg.pucch.sets[1].resources[7].nof_symbols = 2;
cfg.pucch.sets[1].resources[7].start_symbol_idx = 2;
// Item 16
// PUCCH-Resource
// pucch-ResourceId: 16
// startingPRB: 0
// format: format1 (1)
// format1
// initialCyclicShift: 8
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 2
// Item 17
// PUCCH-Resource
// pucch-ResourceId: 17
// startingPRB: 1
// format: format2 (2)
// format2
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 2
// format1: setup (1)
// setup
// format2: setup (1)
// setup
// maxCodeRate: zeroDot25 (2)
for (uint32_t i = 0; i < SRSLTE_PUCCH_NR_MAX_NOF_SETS; i++) {
srslte_pucch_nr_resource_set_t* set = &cfg.pucch.sets[i];
for (uint32_t j = 0; j < set->nof_resources; j++) {
if (set->resources[j].format == SRSLTE_PUCCH_NR_FORMAT_2) {
set->resources[j].max_code_rate = 2; // 0.25
}
}
}
// schedulingRequestResourceToAddModList: 1 item
// Item 0
// SchedulingRequestResourceConfig
// schedulingRequestResourceId: 1
// schedulingRequestID: 0
// periodicityAndOffset: sl40 (10)
// sl40: 8
// resource: 16
// dl-DataToUL-ACK: 7 items
// Item 0
// dl-DataToUL-ACK item: 8
// Item 1
// dl-DataToUL-ACK item: 7
// Item 2
// dl-DataToUL-ACK item: 6
// Item 3
// dl-DataToUL-ACK item: 5
// Item 4
// dl-DataToUL-ACK item: 4
// Item 5
// dl-DataToUL-ACK item: 12
// Item 6
// dl-DataToUL-ACK item: 11
cfg.harq_ack.dl_data_to_ul_ack[0] = 8;
cfg.harq_ack.dl_data_to_ul_ack[1] = 7;
cfg.harq_ack.dl_data_to_ul_ack[2] = 6;
cfg.harq_ack.dl_data_to_ul_ack[3] = 5;
cfg.harq_ack.dl_data_to_ul_ack[4] = 4;
cfg.harq_ack.dl_data_to_ul_ack[5] = 12;
cfg.harq_ack.dl_data_to_ul_ack[6] = 11;
cfg.harq_ack.nof_dl_data_to_ul_ack = 7;
}
/**
@ -245,10 +629,10 @@ public:
std::lock_guard<std::mutex> lock(pending_ul_grant_mutex);
// Save entry
pending_grant_t& pending_grant = pending_ul_grant[tti_tx];
pending_grant.sch_cfg = pusch_cfg;
pending_grant.pid = dci_ul.pid;
pending_grant.enable = true;
pending_ul_grant_t& pending_grant = pending_ul_grant[tti_tx];
pending_grant.sch_cfg = pusch_cfg;
pending_grant.pid = dci_ul.pid;
pending_grant.enable = true;
}
/**
@ -264,7 +648,7 @@ public:
std::lock_guard<std::mutex> lock(pending_ul_grant_mutex);
// Select entry
pending_grant_t& pending_grant = pending_ul_grant[tti_tx];
pending_ul_grant_t& pending_grant = pending_ul_grant[tti_tx];
// If the entry is not active, just return
if (!pending_grant.enable) {
@ -279,6 +663,126 @@ public:
return true;
}
/**
* @brief Stores a received DL DCI into the pending DL grant list
* @param tti_rx The TTI in which the grant was received
* @param dci_dl The DL DCI message to store
*/
void set_dl_pending_grant(uint32_t tti_rx, const srslte_dci_dl_nr_t& dci_dl)
{
// Convert DL DCI to grant
srslte_sch_cfg_nr_t pdsch_cfg = {};
if (srslte_ra_dl_dci_to_grant_nr(&carrier, &cfg.pdsch, &dci_dl, &pdsch_cfg, &pdsch_cfg.grant)) {
ERROR("Computing UL grant");
return;
}
// Calculate DL DCI to PDSCH ACK resource
srslte_pdsch_ack_resource_nr_t ack_resource = {};
if (srslte_ue_dl_nr_pdsch_ack_resource(&cfg.harq_ack, &dci_dl, &ack_resource) < SRSLTE_SUCCESS) {
ERROR("Computing UL ACK resource");
return;
}
// Calculate Receive TTI
tti_rx = TTI_ADD(tti_rx, pdsch_cfg.grant.k);
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_dl_grant_mutex);
// Save entry
pending_dl_grant_t& pending_grant = pending_dl_grant[tti_rx];
pending_grant.sch_cfg = pdsch_cfg;
pending_grant.ack_resource = ack_resource;
pending_grant.pid = dci_dl.pid;
pending_grant.enable = true;
}
/**
* @brief Checks the DL pending grant list if there is any grant to receive for the given receive TTI
* @param tti_rx Current receive TTI
* @param sch_cfg Provides the Shared Channel configuration for the PDSCH transmission
* @param ack_resource Provides the UL ACK resource
* @param pid Provides the HARQ process identifier
* @return true if there is a pending grant for the given TX tti, false otherwise
*/
bool get_dl_pending_grant(uint32_t tti_rx,
srslte_sch_cfg_nr_t& pdsch_cfg,
srslte_pdsch_ack_resource_nr_t& ack_resource,
uint32_t& pid)
{
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_dl_grant_mutex);
// Select entry
pending_dl_grant_t& pending_grant = pending_dl_grant[tti_rx];
// If the entry is not active, just return
if (!pending_grant.enable) {
return false;
}
// Load shared channel configuration and resource
pdsch_cfg = pending_grant.sch_cfg;
ack_resource = pending_grant.ack_resource;
pid = pending_grant.pid;
// Reset entry
pending_grant.enable = false;
return true;
}
/**
* @brief Stores a pending PDSCH ACK into the pending ACK list
* @param tti_rx The TTI in which the PDSCH transmission was received
* @param dci_dl The DL DCI message to store
*/
void set_pending_ack(const uint32_t& tti_rx, const srslte_pdsch_ack_resource_nr_t& ack_resource, const bool& crc_ok)
{
// Calculate Receive TTI
uint32_t tti_tx = TTI_ADD(tti_rx, ack_resource.k1);
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_ack_mutex);
// Select UL transmission time resource
srslte_pdsch_ack_nr_t& ack = pending_ack[tti_tx];
ack.nof_cc = 1;
// Select serving cell
srslte_pdsch_ack_cc_nr_t& ack_cc = ack.cc[ack_resource.scell_idx];
srslte_pdsch_ack_m_nr_t& ack_m = ack_cc.m[ack_cc.M];
ack_cc.M++;
// Set PDSCH transmission information
ack_m.resource = ack_resource;
ack_m.value[0] = crc_ok ? 1 : 0;
ack_m.present = true;
}
bool get_pending_ack(const uint32_t& tti_tx, srslte_pdsch_ack_nr_t& pdsch_ack)
{
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_ack_mutex);
// Select UL transmission time resource
srslte_pdsch_ack_nr_t& ack = pending_ack[tti_tx];
// No pending grant was set
if (ack.nof_cc == 0) {
return false;
}
// Copy data
pdsch_ack = ack;
// Reset list entry
ack = {};
return true;
}
};
} // namespace nr
} // namespace srsue

@ -126,30 +126,10 @@ uint32_t cc_worker::get_buffer_len()
return buffer_sz;
}
bool cc_worker::work_dl()
void cc_worker::decode_pdcch_dl()
{
// Run FFT
srslte_ue_dl_nr_estimate_fft(&ue_dl, &dl_slot_cfg);
// Initialise grants
std::array<srslte_dci_dl_nr_t, 5> dci_dl_rx = {};
std::array<srslte_dci_ul_nr_t, 5> dci_ul_rx = {};
uint32_t nof_found_dci_dl = 0;
uint32_t nof_found_dci_ul = 0;
// Search for RA DCI
if (phy->cfg.pdcch.ra_search_space_present) {
int n_ra = srslte_ue_dl_nr_find_dl_dci(&ue_dl,
&dl_slot_cfg,
phy->cfg.pdcch.ra_rnti,
&dci_dl_rx[nof_found_dci_dl],
(uint32_t)dci_dl_rx.size() - nof_found_dci_dl);
if (n_ra < SRSLTE_SUCCESS) {
ERROR("Error decoding");
return false;
}
nof_found_dci_dl += n_ra;
}
std::array<srslte_dci_dl_nr_t, 5> dci_rx = {};
uint32_t nof_found_dci = 0;
// Search for test RNTI
if (phy->test_rnti > 0) {
@ -157,60 +137,90 @@ bool cc_worker::work_dl()
int n_dl = srslte_ue_dl_nr_find_dl_dci(&ue_dl,
&dl_slot_cfg,
(uint16_t)phy->test_rnti,
&dci_dl_rx[nof_found_dci_dl],
(uint32_t)dci_dl_rx.size() - nof_found_dci_dl);
&dci_rx[nof_found_dci],
(uint32_t)dci_rx.size() - nof_found_dci);
if (n_dl < SRSLTE_SUCCESS) {
ERROR("Error decoding");
return false;
logger.error("Error decoding DL NR-PDCCH for test RNTI");
return;
}
nof_found_dci_dl += n_dl;
nof_found_dci += n_dl;
}
// Search for test UL grants
int n_ul = srslte_ue_dl_nr_find_ul_dci(&ue_dl,
&dl_slot_cfg,
(uint16_t)phy->test_rnti,
&dci_ul_rx[nof_found_dci_ul],
(uint32_t)dci_ul_rx.size() - nof_found_dci_ul);
if (n_ul < SRSLTE_SUCCESS) {
ERROR("Error decoding");
return false;
// Search for RA DCI
if (phy->cfg.pdcch.ra_search_space_present) {
int n_ra = srslte_ue_dl_nr_find_dl_dci(
&ue_dl, &dl_slot_cfg, phy->cfg.pdcch.ra_rnti, &dci_rx[nof_found_dci], (uint32_t)dci_rx.size() - nof_found_dci);
if (n_ra < SRSLTE_SUCCESS) {
logger.error("Error decoding DL NR-PDCCH for RA-RNTI");
return;
}
nof_found_dci_ul += n_ul;
nof_found_dci += n_ra;
}
// Iterate over all UL received grants
for (uint32_t i = 0; i < nof_found_dci_ul; i++) {
// Iterate over all DL received grants
for (uint32_t i = 0; i < nof_found_dci; i++) {
// Log found DCI
if (logger.info.enabled()) {
std::array<char, 512> str;
srslte_dci_ul_nr_to_str(&dci_ul_rx[i], str.data(), str.size());
srslte_dci_dl_nr_to_str(&dci_rx[i], str.data(), str.size());
logger.info("PDCCH: cc=%d, %s", cc_idx, str.data());
}
// Enqueue UL grants
phy->set_ul_pending_grant(dl_slot_cfg.idx, dci_ul_rx[i]);
phy->set_dl_pending_grant(dl_slot_cfg.idx, dci_rx[i]);
}
}
// Iterate over all DL received grants
for (uint32_t i = 0; i < nof_found_dci_dl; i++) {
// Notify MAC about PDCCH found grant
// ... At the moment reset softbuffer locally
srslte_softbuffer_rx_reset(&softbuffer_rx);
void cc_worker::decode_pdcch_ul()
{
std::array<srslte_dci_ul_nr_t, 5> dci_rx = {};
uint32_t nof_found_dci = 0;
// Search for test RNTI
if (phy->test_rnti > 0) {
// Search for test DL grants
int n_dl = srslte_ue_dl_nr_find_ul_dci(&ue_dl,
&dl_slot_cfg,
(uint16_t)phy->test_rnti,
&dci_rx[nof_found_dci],
(uint32_t)dci_rx.size() - nof_found_dci);
if (n_dl < SRSLTE_SUCCESS) {
logger.error("Error decoding DL NR-PDCCH for test RNTI");
return;
}
nof_found_dci += n_dl;
}
// Iterate over all UL received grants
for (uint32_t i = 0; i < nof_found_dci; i++) {
// Log found DCI
if (logger.info.enabled()) {
std::array<char, 512> str;
srslte_dci_dl_nr_to_str(&dci_dl_rx[i], str.data(), str.size());
srslte_dci_ul_nr_to_str(&dci_rx[i], str.data(), str.size());
logger.info("PDCCH: cc=%d, %s", cc_idx, str.data());
}
// Compute DL grant
srslte_sch_cfg_nr_t pdsch_cfg = {};
if (srslte_ra_dl_dci_to_grant_nr(&ue_dl.carrier, &phy->cfg.pdsch, &dci_dl_rx[i], &pdsch_cfg, &pdsch_cfg.grant)) {
ERROR("Computing DL grant");
return false;
}
// Enqueue UL grants
phy->set_ul_pending_grant(dl_slot_cfg.idx, dci_rx[i]);
}
}
bool cc_worker::work_dl()
{
// Run FFT
srslte_ue_dl_nr_estimate_fft(&ue_dl, &dl_slot_cfg);
// Decode PDCCH DL first
decode_pdcch_dl();
// Decode PDCCH UL after
decode_pdcch_ul();
// Get DL grant for this TTI, if available
uint32_t pid = 0;
srslte_sch_cfg_nr_t pdsch_cfg = {};
srslte_pdsch_ack_resource_nr_t ack_resource = {};
if (phy->get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) {
// Get data buffer
srslte::unique_byte_buffer_t data = srslte::make_byte_buffer();
data->N_bytes = pdsch_cfg.grant.tb[0].tbs / 8U;
@ -233,13 +243,16 @@ bool cc_worker::work_dl()
logger.info(pdsch_res[0].payload, pdsch_cfg.grant.tb[0].tbs / 8, "PDSCH: cc=%d, %s", cc_idx, str.data());
}
// Enqueue PDSCH ACK information
phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res[0].crc);
// Notify MAC about PDSCH decoding result
if (pdsch_res[0].crc) {
// Prepare grant
mac_interface_phy_nr::mac_nr_grant_dl_t mac_nr_grant = {};
mac_nr_grant.tb[0] = std::move(data);
mac_nr_grant.pid = dci_dl_rx[i].pid;
mac_nr_grant.rnti = dci_dl_rx[i].rnti;
mac_nr_grant.pid = pid;
mac_nr_grant.rnti = pdsch_cfg.grant.rnti;
mac_nr_grant.tti = dl_slot_cfg.idx;
// Send data to MAC
@ -252,36 +265,70 @@ bool cc_worker::work_dl()
bool cc_worker::work_ul()
{
srslte_sch_cfg_nr_t pusch_cfg = {};
uint32_t pid = 0;
srslte_uci_data_nr_t uci_data = {};
uint32_t pid = 0;
// Gather PDSCH ACK information
srslte_pdsch_ack_nr_t pdsch_ack = {};
bool has_ul_ack = phy->get_pending_ack(ul_slot_cfg.idx, pdsch_ack);
// Request grant to PHY state for this transmit TTI
if (not phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid)) {
// If no grant, return earlier
return true;
srslte_sch_cfg_nr_t pusch_cfg = {};
bool has_pusch_grant = phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid);
// If PDSCH UL AKC is available, load into UCI
if (has_ul_ack) {
pdsch_ack.use_pusch = has_pusch_grant;
if (srslte_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSLTE_SUCCESS) {
ERROR("Filling UCI ACK bits");
return false;
}
}
// Notify MAC about PUSCH found grant
// ...
srslte_softbuffer_tx_reset(&softbuffer_tx);
pusch_cfg.grant.tb[0].softbuffer.tx = &softbuffer_tx;
if (has_pusch_grant) {
// Notify MAC about PUSCH found grant
// ...
srslte_softbuffer_tx_reset(&softbuffer_tx);
pusch_cfg.grant.tb[0].softbuffer.tx = &softbuffer_tx;
// Encode PUSCH transmission
if (srslte_ue_ul_nr_encode_pusch(&ue_ul, &ul_slot_cfg, &pusch_cfg, tx_data.data()) < SRSLTE_SUCCESS) {
ERROR("Encoding PUSCH");
return false;
}
// Encode PUSCH transmission
if (srslte_ue_ul_nr_encode_pusch(&ue_ul, &ul_slot_cfg, &pusch_cfg, tx_data.data()) < SRSLTE_SUCCESS) {
ERROR("Encoding PUSCH");
return false;
}
// PUSCH Logging
if (logger.info.enabled()) {
std::array<char, 512> str;
srslte_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, str.data(), str.size());
logger.info(tx_data.data(),
pusch_cfg.grant.tb[0].tbs / 8,
"PUSCH: cc=%d, %s, tti_tx=%d",
cc_idx,
str.data(),
ul_slot_cfg.idx);
}
} else if (srslte_uci_nr_total_bits(&uci_data.cfg) > 0) {
// Get PUCCH resource
srslte_pucch_nr_resource_t resource = {};
if (srslte_ra_ul_nr_pucch_resource(&phy->cfg.pucch, &uci_data.cfg, &resource) < SRSLTE_SUCCESS) {
ERROR("Selecting PUCCH resource");
return false;
}
// Encode PUCCH message
if (srslte_ue_ul_nr_encode_pucch(&ue_ul, &ul_slot_cfg, &phy->cfg.pucch.common, &resource, &uci_data) <
SRSLTE_SUCCESS) {
ERROR("Encoding PUCCH");
return false;
}
// Logging
if (logger.info.enabled()) {
std::array<char, 512> str;
srslte_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, str.data(), str.size());
logger.info(tx_data.data(),
pusch_cfg.grant.tb[0].tbs / 8,
"PUSCH: cc=%d, %s, tti_tx=%d",
cc_idx,
str.data(),
ul_slot_cfg.idx);
// PUCCH Logging
if (logger.info.enabled()) {
std::array<char, 512> str;
srslte_ue_ul_nr_pucch_info(&resource, &uci_data, str.data(), str.size());
logger.info("PUCCH: cc=%d, %s, tti_tx=%d", cc_idx, str.data(), ul_slot_cfg.idx);
}
}
return true;

Loading…
Cancel
Save