srsLTE/lib/src/phy/phch/dci_nr.c

2150 lines
69 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright 2013-2022 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/utils/bit.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
/**
* Defines minimum size according to TS 38.212 section 7.3.1 DCI Formats:
* If the number of information bits in a DCI format is less than 12 bits, zeros shall be appended to the DCI format
* until the payload size equals 12.
*/
#define DCI_NR_MIN_SIZE 12
static uint32_t dci_nr_freq_resource_size_type1(uint32_t N)
{
if (N == 0) {
return 0;
}
return (int)SRSRAN_CEIL_LOG2(N * (N + 1) / 2.0);
}
static uint32_t dci_nr_freq_resource_size(srsran_resource_alloc_t alloc_type, uint32_t N_RBG, uint32_t N_BWP_RB)
{
// Frequency domain resource assignment
switch (alloc_type) {
case srsran_resource_alloc_type0:
return N_RBG;
case srsran_resource_alloc_type1:
return dci_nr_freq_resource_size_type1(N_BWP_RB);
case srsran_resource_alloc_dynamic:
return SRSRAN_MAX(N_RBG, dci_nr_freq_resource_size_type1(N_BWP_RB)) + 1;
default:
ERROR("Unhandled case");
}
return 0;
}
static uint32_t dci_nr_bwp_id_size(uint32_t N_BWP_RRC)
{
uint32_t N_BWP = N_BWP_RRC;
if (N_BWP_RRC <= 3) {
N_BWP = N_BWP_RRC + 1;
}
return (int)SRSRAN_CEIL_LOG2(N_BWP);
}
static uint32_t dci_nr_time_res_size(uint32_t nof_time_res)
{
if (nof_time_res == 0) {
// 4 bits are necessary for PUSCH default time resource assigment (TS 38.214 Table 6.1.2.1.1-2)
nof_time_res = SRSRAN_MAX_NOF_TIME_RA;
}
return (uint32_t)SRSRAN_CEIL_LOG2(nof_time_res);
}
static uint32_t dci_nr_ptrs_size(const srsran_dci_cfg_nr_t* cfg)
{
// 0 bit if PTRS-UplinkConfig is not configured and transform precoder is disabled, or if transform precoder is
// enabled, or if maxRank=1;
if ((!cfg->pusch_ptrs && !cfg->enable_transform_precoding) || cfg->enable_transform_precoding ||
cfg->nof_ul_layers <= 1) {
return 0;
}
// 2 bits otherwise, where Table 7.3.1.1.2-25 and 7.3.1.1.2-26 are used to indicate the association between
// PTRS port(s) and DMRS port(s) for transmission of one PT-RS port and two PT-RS ports respectively, and
// the DMRS ports are indicated by the Antenna ports field.
return 2;
}
static uint32_t dci_nr_dl_ports_size(const srsran_dci_cfg_nr_t* cfg)
{
uint32_t ret = 4;
if (cfg->pdsch_dmrs_type == srsran_dmrs_sch_type_2) {
ret++;
}
if (cfg->pdsch_dmrs_max_len == srsran_dmrs_sch_len_2) {
ret++;
}
return ret;
}
static uint32_t dci_nr_ul_ports_size(const srsran_dci_cfg_nr_t* cfg)
{
// 2 bits as defined by Tables 7.3.1.1.2-6, if transform precoder is enabled, dmrs-Type=1, and maxLength=1;
if (cfg->enable_transform_precoding == true && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_1 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_1) {
return 2;
}
// 4 bits as defined by Tables 7.3.1.1.2-7, if transform precoder is enabled, dmrs-Type=1, and maxLength=2;
if (cfg->enable_transform_precoding == true && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_1 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_2) {
return 4;
}
// 3 bits as defined by Tables 7.3.1.1.2-8/9/10/11, if transform precoder is disabled, dmrs-Type=1, and maxLength=1
if (cfg->enable_transform_precoding == false && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_1 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_1) {
return 3;
}
// 4 bits as defined by Tables 7.3.1.1.2-12/13/14/15, if transform precoder is disabled, dmrs-Type=1, and
// maxLength=2
if (cfg->enable_transform_precoding == false && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_1 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_2) {
return 4;
}
// 4 bits as defined by Tables 7.3.1.1.2-16/17/18/19, if transform precoder is disabled, dmrs-Type=2, and
// maxLength=1
if (cfg->enable_transform_precoding == false && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_2 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_1) {
return 4;
}
// 5 bits as defined by Tables 7.3.1.1.2-20/21/22/23, if transform precoder is disabled, dmrs-Type=2, and
// maxLength=2
if (cfg->enable_transform_precoding == false && cfg->pusch_dmrs_type == srsran_dmrs_sch_type_2 &&
cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_2) {
return 5;
}
ERROR("Unhandled configuration");
return 0;
}
static uint32_t dci_nr_srs_id_size(const srsran_dci_cfg_nr_t* cfg)
{
uint32_t N_srs = SRSRAN_MIN(1, cfg->nof_srs);
if (cfg->pusch_tx_config_non_codebook) {
uint32_t N = 0;
for (uint32_t k = 1; k < SRSRAN_MIN(cfg->nof_ul_layers, cfg->nof_srs); k++) {
N += cfg->nof_srs / k;
}
return (uint32_t)SRSRAN_CEIL_LOG2(N);
}
return (uint32_t)SRSRAN_CEIL_LOG2(N_srs);
}
// Determines DCI format 0_0 according to TS 38.212 clause 7.3.1.1.1
static uint32_t dci_nr_format_0_0_sizeof(uint32_t N_UL_BWP_RB, const srsran_dci_cfg_nr_t* cfg)
{
uint32_t count = 0;
// Identifier for DCI formats 1 bits
count++;
// For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset
uint32_t N_UL_hop = (cfg->enable_hopping) ? ((N_UL_BWP_RB < 50) ? 1 : 2) : 0;
count += N_UL_hop;
// Frequency domain resource assignment
uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB);
if (N < N_UL_hop) {
return 0;
}
count += N - N_UL_hop;
// Time domain resource assignment 4 bits
count += 4;
// Frequency hopping flag 1 bit
count += 1;
// Modulation and coding scheme 5 bits
count += 5;
// New data indicator 1 bit
count += 1;
// Redundancy version 2 bits
count += 2;
// HARQ process number 4 bits
count += 4;
// TPC command for scheduled PUSCH 2 bits
count += 2;
// UL/SUL indicator 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0
if (cfg->enable_sul) {
count++;
}
return count;
}
static int dci_nr_format_0_0_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
bool is_common_ss = SRSRAN_SEARCH_SPACE_IS_COMMON(msg->ctx.ss_type);
uint32_t trunc = is_common_ss ? q->dci_0_0_common_trunc : 0; // hard-coded bit truncation
uint32_t padding = is_common_ss ? q->dci_0_0_common_padd : q->dci_0_0_ue_padd; // Hard-coded padding
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
uint32_t N_UL_BWP_RB = is_common_ss ? q->cfg.bwp_ul_initial_bw : q->cfg.bwp_ul_active_bw;
// 1st of all, copy DCI context
msg->ctx = dci->ctx;
// Check RNTI type
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c &&
rnti_type != srsran_rnti_type_tc) {
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
*y = 0;
y++;
// For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset
int N_UL_hop = (q->cfg.enable_hopping) ? (N_UL_BWP_RB ? 1 : 2) : 0;
srsran_bit_unpack(dci->frequency_offset, &y, N_UL_hop);
// Frequency domain resource assignment
uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB);
if (N <= N_UL_hop) {
return SRSRAN_ERROR;
}
srsran_bit_unpack(dci->freq_domain_assigment, &y, (int)(N - N_UL_hop - trunc));
// Time domain resource assignment 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, 4);
// Frequency hopping flag 1 bit
srsran_bit_unpack(dci->freq_hopping_flag, &y, 1);
// Modulation and coding scheme 5 bits
srsran_bit_unpack(dci->mcs, &y, 5);
// New data indicator 1 bit
srsran_bit_unpack(dci->ndi, &y, 1);
// Redundancy version 2 bits
srsran_bit_unpack(dci->rv, &y, 2);
// HARQ process number 4 bits
srsran_bit_unpack(dci->pid, &y, 4);
// TPC command for scheduled PUSCH 2 bits
srsran_bit_unpack(dci->tpc, &y, 2);
// Padding goes here
for (uint32_t i = 0; i < padding; i++) {
*(y++) = 0;
}
// UL/SUL indicator 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0
if (q->cfg.enable_sul) {
*(y++) = 0;
}
msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_0_0);
if (msg->nof_bits != y - msg->payload) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload));
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int dci_nr_format_0_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
uint32_t trim = 0; // hard-coded bit trimming
bool enable_hopping = false; // hard-coded PUSCH hopping
uint32_t padding = 8; // Hard-coded padding
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
srsran_search_space_type_t ss_type = msg->ctx.ss_type;
uint32_t N_UL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type) ? q->cfg.bwp_ul_initial_bw : q->cfg.bwp_ul_active_bw;
// Check RNTI type
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c &&
rnti_type != srsran_rnti_type_tc) {
ERROR("Unsupported %s", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
uint32_t nof_bits = srsran_dci_nr_size(q, ss_type, srsran_dci_format_nr_0_0);
if (msg->nof_bits != nof_bits) {
ERROR("Invalid number of bits %d, expected %d", msg->nof_bits, nof_bits);
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
if (*(y++) != 0) {
ERROR("Wrond DCI format");
return SRSRAN_ERROR;
}
// For PUSCH hopping with resource allocation type 1 N UL_hop MSB bits are used to indicate the frequency offset
uint32_t N_UL_hop = (enable_hopping) ? ((N_UL_BWP_RB < 50) ? 1 : 2) : 0;
dci->frequency_offset = srsran_bit_pack(&y, N_UL_hop);
// Frequency domain resource assignment
uint32_t N = dci_nr_freq_resource_size_type1(N_UL_BWP_RB);
dci->freq_domain_assigment = srsran_bit_pack(&y, N - N_UL_hop - trim);
// Time domain resource assignment 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, 4);
// Frequency hopping flag 1 bit
dci->freq_hopping_flag = srsran_bit_pack(&y, 1);
// Modulation and coding scheme 5 bits
dci->mcs = srsran_bit_pack(&y, 5);
// New data indicator 1 bit
dci->ndi = srsran_bit_pack(&y, 1);
// Redundancy version 2 bits
dci->rv = srsran_bit_pack(&y, 2);
// HARQ process number 4 bits
dci->pid = srsran_bit_pack(&y, 4);
// TPC command for scheduled PUSCH 2 bits
dci->tpc = srsran_bit_pack(&y, 2);
// Padding goes here
for (uint32_t i = 0; i < padding; i++) {
y++;
}
// UL/SUL indicator 1 bit for UEs configured with supplementaryUplink in ServingCellConfig, otherwise 0
if (q->cfg.enable_sul) {
dci->sul = srsran_bit_pack(&y, 1);
}
return SRSRAN_SUCCESS;
}
static uint32_t dci_nr_format_0_0_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
// Frequency domain resource assignment
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// Time domain resource assignment 4 bits
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// Frequency hopping flag 1 bit
len = srsran_print_check(str, str_len, len, "hop=%c ", dci->freq_hopping_flag == 0 ? 'n' : 'y');
// Modulation and coding scheme 5 bits
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// New data indicator 1 bit
len = srsran_print_check(str, str_len, len, "ndi=%d ", dci->ndi);
// Redundancy version 2 bits
len = srsran_print_check(str, str_len, len, "rv=%d ", dci->rv);
// HARQ process number 4 bits
len = srsran_print_check(str, str_len, len, "harq_id=%d ", dci->pid);
// TPC command for scheduled PUSCH 2 bits
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
return len;
}
static uint32_t dci_nr_format_0_1_sizeof(const srsran_dci_cfg_nr_t* cfg, srsran_rnti_type_t rnti_type)
{
uint32_t count = 0;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_sp_csi &&
rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 0_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bit
count += 1;
// Carrier indicator 0 or 3 bits
count += cfg->carrier_indicator_size;
// UL/SUL indicator 0 bit for UEs not configured with supplementaryUplink ... otherwise, 1 bit
count += cfg->enable_sul ? 1 : 0;
// Bandwidth part indicator 0, 1 or 2 bits
count += dci_nr_bwp_id_size(cfg->nof_ul_bwp);
// Frequency domain resource assignment
count += dci_nr_freq_resource_size(cfg->pusch_alloc_type, cfg->nof_rb_groups, cfg->bwp_ul_active_bw);
// Time domain resource assigment - 0, 1, 2, 3, or 4 bits
count += dci_nr_time_res_size(cfg->nof_ul_time_res);
// Frequency hopping flag - 0 or 1 bit:
if (cfg->pusch_alloc_type == srsran_resource_alloc_type0 || !cfg->enable_hopping) {
count += 0;
} else {
count += 1;
}
// Modulation and coding scheme 5 bits
count += 5;
// New data indicator 1 bit
count += 1;
// Redundancy version 2 bits
count += 2;
// HARQ process number 4 bits
count += 4;
// 1st DAI - 1 or 2 bits
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_semi_static) {
count += 1;
} else {
count += 2;
}
// 2st DAI - 0 or 2 bits
if (cfg->dynamic_dual_harq_ack_codebook) {
count += 2;
}
// TPC command for scheduled PUSCH 2 bits
count += 2;
// SRS resource indicator
count += dci_nr_srs_id_size(cfg);
// Precoding information and number of layers
if (!cfg->pusch_tx_config_non_codebook && cfg->nof_ul_layers > 1) {
ERROR("Not implemented");
return 0;
}
// Antenna ports
count += dci_nr_ul_ports_size(cfg);
// SRS request - 2 or 3 bits
count += cfg->enable_sul ? 3 : 2;
// CSI request - 0, 1, 2, 3, 4, 5, or 6 bits
count += SRSRAN_MIN(6, cfg->report_trigger_size);
// CBG transmission information - 0, 2, 4, 6, or 8 bits
count += cfg->pusch_nof_cbg;
// PTRS-DMRS association - 0 or 2 bits
count += dci_nr_ptrs_size(cfg);
// beta_offset indicator 0 or 2 bits
if (cfg->pusch_dynamic_betas) {
count += 2;
}
// DMRS sequence initialization - 0 or 1 bit
if (!cfg->enable_transform_precoding) {
count += 1;
}
// UL-SCH indicator 1 bit
count += 1;
return count;
}
static int dci_nr_format_0_1_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
srsran_rnti_type_t rnti_type = dci->ctx.rnti_type;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_sp_csi &&
rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 0_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
uint8_t* y = msg->payload;
// Identifier for DCI formats 1 bit
*(y++) = 0; // The value of this bit field is always set to 0, indicating an UL DCI format
// Carrier indicator 0 or 3 bits
srsran_bit_unpack(dci->cc_id, &y, cfg->carrier_indicator_size);
// UL/SUL indicator 0 bit for UEs not configured with supplementaryUplink ... otherwise, 1 bit
srsran_bit_unpack(dci->sul, &y, cfg->enable_sul ? 1 : 0);
// Bandwidth part indicator 0, 1 or 2 bits
srsran_bit_unpack(dci->bwp_id, &y, dci_nr_bwp_id_size(cfg->nof_ul_bwp));
// Frequency domain resource assignment
srsran_bit_unpack(dci->freq_domain_assigment,
&y,
dci_nr_freq_resource_size(cfg->pusch_alloc_type, cfg->nof_rb_groups, cfg->bwp_ul_active_bw));
// Time domain resource assigment - 0, 1, 2, 3, or 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, dci_nr_time_res_size(cfg->nof_ul_time_res));
// Frequency hopping flag - 0 or 1 bit:
if (cfg->pusch_alloc_type != srsran_resource_alloc_type0 && cfg->enable_hopping) {
srsran_bit_unpack(dci->freq_hopping_flag, &y, 1);
}
// Modulation and coding scheme 5 bits
srsran_bit_unpack(dci->mcs, &y, 5);
// New data indicator 1 bit
srsran_bit_unpack(dci->ndi, &y, 1);
// Redundancy version 2 bits
srsran_bit_unpack(dci->rv, &y, 2);
// HARQ process number 4 bits
srsran_bit_unpack(dci->pid, &y, 4);
// 1st DAI - 1 or 2 bits
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_semi_static) {
srsran_bit_unpack(dci->dai1, &y, 1);
} else {
srsran_bit_unpack(dci->dai1, &y, 2);
}
// 2st DAI - 0 or 2 bits
if (cfg->dynamic_dual_harq_ack_codebook) {
srsran_bit_unpack(dci->dai2, &y, 2);
}
// TPC command for scheduled PUSCH 2 bits
srsran_bit_unpack(dci->tpc, &y, 2);
// SRS resource indicator
srsran_bit_unpack(dci->srs_id, &y, dci_nr_srs_id_size(cfg));
// Precoding information and number of layers
if (cfg->pusch_tx_config_non_codebook) {
ERROR("Not implemented");
return 0;
}
// Antenna ports
srsran_bit_unpack(dci->ports, &y, dci_nr_ul_ports_size(cfg));
// SRS request - 2 or 3 bits
srsran_bit_unpack(dci->srs_request, &y, cfg->enable_sul ? 3 : 2);
// CSI request - 0, 1, 2, 3, 4, 5, or 6 bits
srsran_bit_unpack(dci->csi_request, &y, SRSRAN_MIN(6, cfg->report_trigger_size));
// CBG transmission information - 0, 2, 4, 6, or 8 bits
srsran_bit_unpack(dci->cbg_info, &y, cfg->pusch_nof_cbg);
// PTRS-DMRS association - 0 or 2 bits
srsran_bit_unpack(dci->ptrs_id, &y, dci_nr_ptrs_size(cfg));
// beta_offset indicator 0 or 2 bits
if (cfg->pusch_dynamic_betas) {
srsran_bit_unpack(dci->beta_id, &y, 2);
}
// DMRS sequence initialization - 0 or 1 bit
if (!cfg->enable_transform_precoding) {
srsran_bit_unpack(dci->dmrs_id, &y, 1);
}
// UL-SCH indicator 1 bit
srsran_bit_unpack(dci->ulsch, &y, 1);
msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_0_1);
if (msg->nof_bits != y - msg->payload) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload));
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int dci_nr_format_0_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
srsran_rnti_type_t rnti_type = dci->ctx.rnti_type;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_sp_csi &&
rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 0_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
uint8_t* y = msg->payload;
// Identifier for DCI formats 1 bits
if (*(y++) != 0) {
ERROR("Wrond DCI format");
return SRSRAN_ERROR;
}
// Carrier indicator 0 or 3 bits
dci->cc_id = srsran_bit_pack(&y, SRSRAN_MIN(cfg->carrier_indicator_size, 3));
// UL/SUL indicator 0 bit for UEs not configured with supplementaryUplink ... otherwise, 1 bit
dci->sul = srsran_bit_pack(&y, cfg->enable_sul ? 1 : 0);
// Bandwidth part indicator 0, 1 or 2 bits
dci->bwp_id = srsran_bit_pack(&y, dci_nr_bwp_id_size(cfg->nof_ul_bwp));
// Frequency domain resource assignment
dci->freq_domain_assigment =
srsran_bit_pack(&y, dci_nr_freq_resource_size(cfg->pusch_alloc_type, cfg->nof_rb_groups, cfg->bwp_ul_active_bw));
// Time domain resource assigment - 0, 1, 2, 3, or 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, dci_nr_time_res_size(cfg->nof_ul_time_res));
// Frequency hopping flag - 0 or 1 bit:
if (cfg->pusch_alloc_type != srsran_resource_alloc_type0 && cfg->enable_hopping) {
dci->freq_hopping_flag = srsran_bit_pack(&y, 1);
}
// Modulation and coding scheme 5 bits
dci->mcs = srsran_bit_pack(&y, 5);
// New data indicator 1 bit
dci->ndi = srsran_bit_pack(&y, 1);
// Redundancy version 2 bits
dci->rv = srsran_bit_pack(&y, 2);
// HARQ process number 4 bits
dci->pid = srsran_bit_pack(&y, 4);
// 1st DAI - 1 or 2 bits
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_semi_static) {
dci->dai1 = srsran_bit_pack(&y, 1);
} else {
dci->dai1 = srsran_bit_pack(&y, 2);
}
// 2st DAI - 0 or 2 bits
if (cfg->dynamic_dual_harq_ack_codebook) {
dci->dai2 = srsran_bit_pack(&y, 2);
}
// TPC command for scheduled PUSCH 2 bits
dci->tpc = srsran_bit_pack(&y, 2);
// SRS resource indicator
dci->srs_id = srsran_bit_pack(&y, dci_nr_srs_id_size(cfg));
// Precoding information and number of layers
if (cfg->pusch_tx_config_non_codebook) {
ERROR("Not implemented");
return 0;
}
// Antenna ports
if (!cfg->enable_transform_precoding && cfg->pusch_dmrs_max_len == srsran_dmrs_sch_len_1) {
dci->ports = srsran_bit_pack(&y, 3);
} else {
ERROR("Not implemented");
return 0;
}
// SRS request - 2 or 3 bits
dci->srs_request = srsran_bit_pack(&y, cfg->enable_sul ? 3 : 2);
// CSI request - 0, 1, 2, 3, 4, 5, or 6 bits
dci->csi_request = srsran_bit_pack(&y, SRSRAN_MIN(6, cfg->report_trigger_size));
// CBG transmission information - 0, 2, 4, 6, or 8 bits
dci->cbg_info = srsran_bit_pack(&y, cfg->pusch_nof_cbg);
// PTRS-DMRS association - 0 or 2 bits
dci->ptrs_id = srsran_bit_pack(&y, dci_nr_ptrs_size(cfg));
// beta_offset indicator 0 or 2 bits
if (cfg->pusch_dynamic_betas) {
dci->beta_id = srsran_bit_pack(&y, 2);
}
// DMRS sequence initialization - 0 or 1 bit
if (!cfg->enable_transform_precoding) {
dci->dmrs_id = srsran_bit_pack(&y, 1);
}
// UL-SCH indicator 1 bit
dci->ulsch = srsran_bit_pack(&y, 1);
if (msg->nof_bits != y - msg->payload) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload));
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static uint32_t
dci_nr_format_0_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
// Carrier indicator 0 or 3 bits
if (cfg->carrier_indicator_size) {
len = srsran_print_check(str, str_len, len, "cc=%d ", dci->cc_id);
}
// UL/SUL indicator 0 bit for UEs not configured with supplementaryUplink ... otherwise, 1 bit
if (cfg->enable_sul) {
len = srsran_print_check(str, str_len, len, "sul=%d ", dci->sul);
}
// Bandwidth part indicator 0, 1 or 2 bits
if (dci_nr_bwp_id_size(cfg->nof_ul_bwp) > 0) {
len = srsran_print_check(str, str_len, len, "bwp=%d ", dci->bwp_id);
}
// Frequency domain resource assignment
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// Time domain resource assigment - 0, 1, 2, 3, or 4 bits
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// Frequency hopping flag - 0 or 1 bit:
if (cfg->pusch_alloc_type != srsran_resource_alloc_type0 && cfg->enable_hopping) {
len = srsran_print_check(str, str_len, len, "hop=0x%x ", dci->freq_hopping_flag);
}
// Modulation and coding scheme 5 bits
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// New data indicator 1 bit
len = srsran_print_check(str, str_len, len, "ndi=%d ", dci->ndi);
// Redundancy version 2 bits
len = srsran_print_check(str, str_len, len, "rv=%d ", dci->rv);
// HARQ process number 4 bits
len = srsran_print_check(str, str_len, len, "harq_id=%d ", dci->pid);
// 1st DAI - 1 or 2 bits
len = srsran_print_check(str, str_len, len, "dai1=%d ", dci->dai1);
// 2st DAI - 0 or 2 bits
if (cfg->dynamic_dual_harq_ack_codebook) {
len = srsran_print_check(str, str_len, len, "dai2=%d ", dci->dai2);
}
// TPC command for scheduled PUSCH 2 bits
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
// SRS resource indicator
if (dci_nr_srs_id_size(cfg) > 0) {
len = srsran_print_check(str, str_len, len, "srs_id=%d ", dci->srs_id);
}
// Precoding information and number of layers
if (cfg->pusch_tx_config_non_codebook) {
ERROR("Not implemented");
return 0;
}
// Antenna ports
if (dci_nr_ul_ports_size(cfg)) {
len = srsran_print_check(str, str_len, len, "ports=%d ", dci->ports);
}
// SRS request - 2 bits
len = srsran_print_check(str, str_len, len, "srs_req=%d ", dci->srs_request);
// CSI request - 0, 1, 2, 3, 4, 5, or 6 bits
if (cfg->report_trigger_size > 0) {
len = srsran_print_check(str, str_len, len, "csi_req=%d ", dci->csi_request);
}
// CBG transmission information - 0, 2, 4, 6, or 8 bits
if (cfg->pusch_nof_cbg > 0) {
len = srsran_print_check(str, str_len, len, "cbg_info=%d ", dci->cbg_info);
}
// PTRS-DMRS association - 0 or 2 bits
if (dci_nr_ptrs_size(cfg) > 0) {
len = srsran_print_check(str, str_len, len, "ptrs_id=%d ", dci->ptrs_id);
}
// beta_offset indicator 0 or 2 bits
if (cfg->pusch_dynamic_betas) {
len = srsran_print_check(str, str_len, len, "beta_id=%d ", dci->beta_id);
}
// DMRS sequence initialization - 0 or 1 bit
if (!cfg->enable_transform_precoding) {
len = srsran_print_check(str, str_len, len, "dmrs_id=%d ", dci->dmrs_id);
}
// UL-SCH indicator 1 bit
len = srsran_print_check(str, str_len, len, "ulsch=%d ", dci->ulsch);
return len;
}
static uint32_t dci_nr_rar_sizeof()
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint32_t count = 0;
// Frequency hopping flag - 1 bit
count += 1;
// PUSCH frequency resource allocation - 14 bits
count += 14;
// PUSCH time resource allocation - 4 bits
count += 4;
// MCS - 4 bits
count += 4;
// TPC command for PUSCH - 3 bits
count += 3;
// CSI request - 1 bits
count += 1;
return count;
}
static int dci_nr_rar_pack(const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint8_t* y = msg->payload;
// Frequency hopping flag - 1 bit
srsran_bit_unpack(dci->freq_hopping_flag, &y, 1);
// PUSCH frequency resource allocation - 14 bits
srsran_bit_unpack(dci->freq_domain_assigment, &y, 14);
// PUSCH time resource allocation - 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, 4);
// MCS - 4 bits
srsran_bit_unpack(dci->mcs, &y, 4);
// TPC command for PUSCH - 3 bits
srsran_bit_unpack(dci->tpc, &y, 3);
// CSI request - 1 bits
srsran_bit_unpack(dci->csi_request, &y, 1);
return SRSRAN_SUCCESS;
}
static int dci_nr_rar_unpack(srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint8_t* y = msg->payload;
// Copy DCI MSG fields
dci->ctx = msg->ctx;
// Frequency hopping flag - 1 bit
dci->freq_hopping_flag = srsran_bit_pack(&y, 1);
// PUSCH frequency resource allocation - 14 bits
dci->freq_domain_assigment = srsran_bit_pack(&y, 14);
// PUSCH time resource allocation - 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, 4);
// MCS -4 bits
dci->mcs = srsran_bit_pack(&y, 4);
// TPC command for PUSCH - 3 bits
dci->tpc = srsran_bit_pack(&y, 3);
// CSI request - 1 bits
dci->csi_request = srsran_bit_pack(&y, 1);
return SRSRAN_SUCCESS;
}
static uint32_t dci_nr_rar_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
// Frequency hopping flag
len = srsran_print_check(str, str_len, len, "hop=%d ", dci->freq_hopping_flag);
// PUSCH frequency resource allocation
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// PUSCH time resource allocation
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// Modulation and coding scheme
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// TPC command for scheduled PUSCH
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
// CSI request
len = srsran_print_check(str, str_len, len, "csi=%d ", dci->csi_request);
return len;
}
static uint32_t dci_nr_format_1_0_sizeof(uint32_t N_DL_BWP_RB, srsran_rnti_type_t rnti_type)
{
uint32_t count = 0;
// Identifier for DCI formats 1 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 1;
}
if (rnti_type == srsran_rnti_type_p) {
// Short Messages Indicator 2 bits
count += 2;
// Short Messages 8 bits
count += 8;
}
// Frequency domain resource assignment
int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB);
if (N < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
count += N;
// Time domain resource assignment 4 bits
count += 4;
// VRB-to-PRB mapping 1 bit
count += 1;
// Modulation and coding scheme 5 bits
count += 5;
// TB scaling 2 bits
if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) {
count += 2;
}
// New data indicator 1 bit
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 1;
}
// Redundancy version 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) {
count += 2;
}
// HARQ process number 4 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 4;
}
// System information indicator 1 bit
if (rnti_type == srsran_rnti_type_si) {
count += 1;
}
// Downlink assignment index 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 2;
}
// TPC command for scheduled PUCCH 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 2;
}
// PUCCH resource indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 3;
}
// PDSCH-to-HARQ_feedback timing indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
count += 3;
}
// Reserved bits ...
if (rnti_type == srsran_rnti_type_p) {
// ... 6 bits
count += 2;
} else if (rnti_type == srsran_rnti_type_si) {
// ... 15 bits
count += 15;
} else if (rnti_type == srsran_rnti_type_ra) {
// ... 16 bits
count += 16;
}
return count;
}
static int dci_nr_format_1_0_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
srsran_search_space_type_t ss_type = dci->ctx.ss_type;
uint32_t N_DL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)
? (q->cfg.coreset0_bw == 0) ? q->cfg.bwp_dl_initial_bw : q->cfg.coreset0_bw
: q->cfg.bwp_dl_active_bw;
// Identifier for DCI formats 1 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
*y = 1;
y++;
}
if (rnti_type == srsran_rnti_type_p) {
// Short Messages Indicator 2 bits
srsran_bit_unpack(dci->smi, &y, 2);
// Short Messages 8 bits
srsran_bit_unpack(dci->sm, &y, 8);
}
// Frequency domain resource assignment
int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB);
if (N < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
srsran_bit_unpack(dci->freq_domain_assigment, &y, N);
// Time domain resource assignment 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, 4);
// VRB-to-PRB mapping 1 bit
srsran_bit_unpack(dci->vrb_to_prb_mapping, &y, 1);
// Modulation and coding scheme 5 bits
srsran_bit_unpack(dci->mcs, &y, 5);
// TB scaling 2 bits
if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) {
srsran_bit_unpack(dci->tb_scaling, &y, 2);
}
// New data indicator 1 bit
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->ndi, &y, 1);
}
// Redundancy version 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->rv, &y, 2);
}
// HARQ process number 4 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->pid, &y, 4);
}
// System information indicator 1 bit
if (rnti_type == srsran_rnti_type_si) {
srsran_bit_unpack(dci->sii, &y, 1);
}
// Downlink assignment index 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->dai, &y, 2);
}
// TPC command for scheduled PUCCH 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->tpc, &y, 2);
}
// PUCCH resource indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->pucch_resource, &y, 3);
}
// PDSCH-to-HARQ_feedback timing indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
srsran_bit_unpack(dci->harq_feedback, &y, 3);
}
// Reserved bits ...
if (rnti_type == srsran_rnti_type_p) {
// ... 6 bits
srsran_bit_unpack(dci->reserved, &y, 6);
} else if (rnti_type == srsran_rnti_type_si) {
// ... 15 bits
srsran_bit_unpack(dci->reserved, &y, 15);
} else if (rnti_type == srsran_rnti_type_ra) {
// ... 16 bits
srsran_bit_unpack(dci->reserved, &y, 16);
}
msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_1_0);
uint32_t nof_bits = (uint32_t)(y - msg->payload);
if (msg->nof_bits != nof_bits) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, nof_bits);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int dci_nr_format_1_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci)
{
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
srsran_search_space_type_t ss_type = msg->ctx.ss_type;
uint32_t N_DL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)
? (q->cfg.coreset0_bw == 0) ? q->cfg.bwp_dl_initial_bw : q->cfg.coreset0_bw
: q->cfg.bwp_dl_active_bw;
uint32_t nof_bits = srsran_dci_nr_size(q, ss_type, srsran_dci_format_nr_1_0);
if (msg->nof_bits != nof_bits) {
ERROR("Invalid number of bits %d, expected %d", msg->nof_bits, nof_bits);
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
// The value of this bit field is always set to 1, indicating a DL DCI format
if (*(y++) != 1) {
ERROR("Wrond DCI format");
return SRSRAN_ERROR;
}
}
if (rnti_type == srsran_rnti_type_p) {
// Short Messages Indicator 2 bits
dci->smi = srsran_bit_pack(&y, 2);
// Short Messages 8 bits
dci->sm = srsran_bit_pack(&y, 8);
}
// Frequency domain resource assignment
int N = dci_nr_freq_resource_size_type1(N_DL_BWP_RB);
if (N < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
dci->freq_domain_assigment = srsran_bit_pack(&y, N);
// Time domain resource assignment 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, 4);
// VRB-to-PRB mapping 1 bit
dci->vrb_to_prb_mapping = srsran_bit_pack(&y, 1);
// Modulation and coding scheme 5 bits
dci->mcs = srsran_bit_pack(&y, 5);
// TB scaling 2 bits
if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) {
dci->tb_scaling = srsran_bit_pack(&y, 2);
}
// New data indicator 1 bit
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->ndi = srsran_bit_pack(&y, 1);
}
// Redundancy version 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) {
dci->rv = srsran_bit_pack(&y, 2);
}
// HARQ process number 4 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->pid = srsran_bit_pack(&y, 4);
}
// System information indicator 1 bit
if (rnti_type == srsran_rnti_type_si) {
dci->sii = srsran_bit_pack(&y, 1);
}
// Downlink assignment index 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->dai = srsran_bit_pack(&y, 2);
}
// TPC command for scheduled PUCCH 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->tpc = srsran_bit_pack(&y, 2);
}
// PUCCH resource indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->pucch_resource = srsran_bit_pack(&y, 3);
}
// PDSCH-to-HARQ_feedback timing indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
dci->harq_feedback = srsran_bit_pack(&y, 3);
}
// Reserved bits ...
if (rnti_type == srsran_rnti_type_p) {
// ... 6 bits
dci->reserved = srsran_bit_pack(&y, 6);
} else if (rnti_type == srsran_rnti_type_si) {
// ... 15 bits
dci->reserved = srsran_bit_pack(&y, 15);
} else if (rnti_type == srsran_rnti_type_ra) {
// ... 16 bits
dci->reserved = srsran_bit_pack(&y, 16);
}
if (msg->nof_bits != y - msg->payload) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload));
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static uint32_t dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
srsran_rnti_type_t rnti_type = dci->ctx.rnti_type;
if (rnti_type == srsran_rnti_type_p) {
len = srsran_print_check(str, str_len, len, "smi=%d sm=%d ", dci->smi, dci->sm);
}
// Frequency domain resource assignment
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// Time domain resource assignment 4 bits
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// VRB-to-PRB mapping 1 bit
len = srsran_print_check(str, str_len, len, "vrb_to_prb_map=%d ", dci->vrb_to_prb_mapping);
// Modulation and coding scheme 5 bits
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// TB scaling 2 bits
if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_ra) {
len = srsran_print_check(str, str_len, len, "tb_scaling=%d ", dci->tb_scaling);
}
// New data indicator 1 bit
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "ndi=%d ", dci->ndi);
}
// Redundancy version 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "rv=%d ", dci->rv);
}
// HARQ process number 4 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "harq_id=%d ", dci->pid);
}
// System information indicator 1 bit
if (rnti_type == srsran_rnti_type_si) {
len = srsran_print_check(str, str_len, len, "sii=%d ", dci->sii);
len = srsran_print_check(str, str_len, len, "coreset0_bw=%d ", dci->coreset0_bw);
}
// Downlink assignment index 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "dai=%d ", dci->dai);
}
// TPC command for scheduled PUCCH 2 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "pucch_tpc=%d ", dci->tpc);
}
// PUCCH resource indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "pucch_res=%d ", dci->pucch_resource);
}
// PDSCH-to-HARQ_feedback timing indicator 3 bits
if (rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_tc) {
len = srsran_print_check(str, str_len, len, "harq_feedback=%d ", dci->harq_feedback);
}
// Reserved bits ...
if (rnti_type == srsran_rnti_type_p || rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_ra) {
len = srsran_print_check(str, str_len, len, "reserved=0x%x ", dci->reserved);
}
return len;
}
static uint32_t dci_nr_format_1_1_sizeof(const srsran_dci_cfg_nr_t* cfg, srsran_rnti_type_t rnti_type)
{
int count = 0;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 1_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
count += 1;
// Carrier indicator 0 or 3 bits
count += (int)cfg->carrier_indicator_size;
// Bandwidth part indicator 0, 1 or 2 bits
count += (int)dci_nr_bwp_id_size(cfg->nof_dl_bwp);
// Frequency domain resource assignment
count += dci_nr_freq_resource_size(cfg->pdsch_alloc_type, cfg->nof_rb_groups, cfg->bwp_dl_active_bw);
// Time domain resource assignment 0, 1, 2, 3, or 4 bits
count += dci_nr_time_res_size(cfg->nof_dl_time_res);
// VRB-to-PRB mapping 0 or 1
if (cfg->pdsch_alloc_type != srsran_resource_alloc_type0 && cfg->pdsch_inter_prb_to_prb) {
count += 1;
}
// PRB bundling size indicator 0 or 1 bits
// ... not implemented
// Rate matching indicator 0, 1, or 2 bits
if (cfg->pdsch_rm_pattern1) {
count += 1;
}
if (cfg->pdsch_rm_pattern2) {
count += 1;
}
// ZP CSI-RS trigger - 0, 1, or 2 bits
count += (int)SRSRAN_CEIL_LOG2(cfg->nof_aperiodic_zp + 1);
// For transport block 1:
// Modulation and coding scheme 5 bits
count += 5;
// New data indicator 1 bit
count += 1;
// Redundancy version 2 bits
count += 2;
// For transport block 2:
if (cfg->pdsch_2cw) {
// Modulation and coding scheme 5 bits
count += 5;
// New data indicator 1 bit
count += 1;
// Redundancy version 2 bits
count += 2;
}
// HARQ process number 4 bits
count += 4;
// Downlink assignment index (dynamic HARQ-ACK codebook only)
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_dynamic) {
if (cfg->multiple_scell) {
count += 4;
} else {
count += 2;
}
}
// TPC command for scheduled PUCCH 2 bits
count += 2;
// PUCCH resource indicator 3 bits
count += 3;
// PDSCH-to-HARQ_feedback timing indicator 0, 1, 2, or 3 bits
count += (int)SRSRAN_CEIL_LOG2(cfg->nof_dl_to_ul_ack);
// Antenna port(s) 4, 5, or 6 bits
count += dci_nr_dl_ports_size(cfg);
// Transmission configuration indication 0 or 3 bits
if (cfg->pdsch_tci) {
count += 3;
}
// SRS request 2 or 3 bits
count += cfg->enable_sul ? 3 : 2;
// CBG transmission information (CBGTI) 0, 2, 4, 6, or 8 bits
count += cfg->pdsch_nof_cbg;
// CBG flushing out information (CBGFI) 0 or 1 bit
if (cfg->pdsch_cbg_flush) {
count += 1;
}
// DMRS sequence initialization 1 bit
count += 1;
return count;
}
static int dci_nr_format_1_1_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 1_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
*(y++) = 1;
// Carrier indicator 0 or 3 bits
srsran_bit_unpack(dci->cc_id, &y, cfg->carrier_indicator_size);
// Bandwidth part indicator 0, 1 or 2 bits
srsran_bit_unpack(dci->bwp_id, &y, dci_nr_bwp_id_size(cfg->nof_dl_bwp));
// Frequency domain resource assignment
srsran_bit_unpack(dci->freq_domain_assigment,
&y,
dci_nr_freq_resource_size(cfg->pdsch_alloc_type, cfg->nof_rb_groups, cfg->bwp_dl_active_bw));
// Time domain resource assignment 0, 1, 2, 3, or 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, dci_nr_time_res_size(cfg->nof_dl_time_res));
// VRB-to-PRB mapping 0 or 1
if (cfg->pdsch_alloc_type != srsran_resource_alloc_type0 && cfg->pdsch_inter_prb_to_prb) {
srsran_bit_unpack(dci->vrb_to_prb_mapping, &y, 1);
}
// PRB bundling size indicator 0 or 1 bits
// ... not implemented
// Rate matching indicator 0, 1, or 2 bits
if (cfg->pdsch_rm_pattern1) {
srsran_bit_unpack(dci->rm_pattern1, &y, 1);
}
if (cfg->pdsch_rm_pattern2) {
srsran_bit_unpack(dci->rm_pattern2, &y, 1);
}
// ZP CSI-RS trigger - 0, 1, or 2 bits
srsran_bit_unpack(dci->zp_csi_rs_id, &y, SRSRAN_CEIL_LOG2(cfg->nof_aperiodic_zp + 1));
// For transport block 1:
// Modulation and coding scheme 5 bits
srsran_bit_unpack(dci->mcs, &y, 5);
// New data indicator 1 bit
srsran_bit_unpack(dci->ndi, &y, 1);
// Redundancy version 2 bits
srsran_bit_unpack(dci->rv, &y, 2);
// For transport block 2:
if (cfg->pdsch_2cw) {
// Modulation and coding scheme 5 bits
srsran_bit_unpack(dci->mcs2, &y, 5);
// New data indicator 1 bit
srsran_bit_unpack(dci->ndi2, &y, 1);
// Redundancy version 2 bits
srsran_bit_unpack(dci->rv2, &y, 2);
}
// HARQ process number 4 bits
srsran_bit_unpack(dci->pid, &y, 4);
// Downlink assignment index (dynamic HARQ-ACK codebook only)
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_dynamic) {
if (cfg->multiple_scell) {
srsran_bit_unpack(dci->dai, &y, 4);
} else {
srsran_bit_unpack(dci->dai, &y, 2);
}
}
// TPC command for scheduled PUCCH 2 bits
srsran_bit_unpack(dci->tpc, &y, 2);
// PUCCH resource indicator 3 bits
srsran_bit_unpack(dci->pucch_resource, &y, 3);
// PDSCH-to-HARQ_feedback timing indicator 0, 1, 2, or 3 bits
srsran_bit_unpack(dci->harq_feedback, &y, (int)SRSRAN_CEIL_LOG2(cfg->nof_dl_to_ul_ack));
// Antenna port(s) 4, 5, or 6 bits
srsran_bit_unpack(dci->ports, &y, dci_nr_dl_ports_size(cfg));
// Transmission configuration indication 0 or 3 bits
if (cfg->pdsch_tci) {
srsran_bit_unpack(dci->tci, &y, 3);
}
// SRS request 2 or 3 bits
srsran_bit_unpack(dci->srs_request, &y, cfg->enable_sul ? 3 : 2);
// CBG transmission information (CBGTI) 0, 2, 4, 6, or 8 bits
srsran_bit_unpack(dci->cbg_info, &y, cfg->pdsch_nof_cbg);
// CBG flushing out information (CBGFI) 0 or 1 bit
if (cfg->pdsch_cbg_flush) {
srsran_bit_unpack(dci->cbg_flush, &y, 1);
}
// DMRS sequence initialization 1 bit
srsran_bit_unpack(dci->dmrs_id, &y, 1);
msg->nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_1_1);
if (msg->nof_bits != y - msg->payload) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", msg->nof_bits, (int)(y - msg->payload));
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int dci_nr_format_1_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci)
{
uint8_t* y = msg->payload;
srsran_rnti_type_t rnti_type = msg->ctx.rnti_type;
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) {
ERROR("Invalid RNTI (%s) for format 1_1", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
uint32_t nof_bits = srsran_dci_nr_size(q, msg->ctx.ss_type, srsran_dci_format_nr_1_1);
if (msg->nof_bits != nof_bits) {
ERROR("Invalid number of bits %d, expected %d", msg->nof_bits, nof_bits);
return SRSRAN_ERROR;
}
// Identifier for DCI formats 1 bits
// The value of this bit field is always set to 1, indicating a DL DCI format
if (*(y++) != 1) {
ERROR("Wrond DCI format");
return SRSRAN_ERROR;
}
// Carrier indicator 0 or 3 bits
dci->cc_id = srsran_bit_pack(&y, cfg->carrier_indicator_size);
// Bandwidth part indicator 0, 1 or 2 bits
dci->bwp_id = srsran_bit_pack(&y, dci_nr_bwp_id_size(cfg->nof_dl_bwp));
// Frequency domain resource assignment
dci->freq_domain_assigment =
srsran_bit_pack(&y, dci_nr_freq_resource_size(cfg->pdsch_alloc_type, cfg->nof_rb_groups, cfg->bwp_dl_active_bw));
// Time domain resource assignment 0, 1, 2, 3, or 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, dci_nr_time_res_size(cfg->nof_dl_time_res));
// VRB-to-PRB mapping 0 or 1
if (cfg->pdsch_alloc_type != srsran_resource_alloc_type0 && cfg->pdsch_inter_prb_to_prb) {
dci->vrb_to_prb_mapping = srsran_bit_pack(&y, 1);
}
// PRB bundling size indicator 0 or 1 bits
// ... not implemented
// Rate matching indicator 0, 1, or 2 bits
if (cfg->pdsch_rm_pattern1) {
dci->rm_pattern1 = srsran_bit_pack(&y, 1);
}
if (cfg->pdsch_rm_pattern2) {
dci->rm_pattern2 = srsran_bit_pack(&y, 1);
}
// ZP CSI-RS trigger - 0, 1, or 2 bits
dci->zp_csi_rs_id = srsran_bit_pack(&y, SRSRAN_CEIL_LOG2(cfg->nof_aperiodic_zp + 1));
// For transport block 1:
// Modulation and coding scheme 5 bits
dci->mcs = srsran_bit_pack(&y, 5);
// New data indicator 1 bit
dci->ndi = srsran_bit_pack(&y, 1);
// Redundancy version 2 bits
dci->rv = srsran_bit_pack(&y, 2);
// For transport block 2:
if (cfg->pdsch_2cw) {
// Modulation and coding scheme 5 bits
dci->mcs2 = srsran_bit_pack(&y, 5);
// New data indicator 1 bit
dci->ndi2 = srsran_bit_pack(&y, 1);
// Redundancy version 2 bits
dci->rv2 = srsran_bit_pack(&y, 2);
}
// HARQ process number 4 bits
dci->pid = srsran_bit_pack(&y, 4);
// Downlink assignment index (dynamic HARQ-ACK codebook only)
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_dynamic) {
if (cfg->multiple_scell) {
dci->dai = srsran_bit_pack(&y, 4);
} else {
dci->dai = srsran_bit_pack(&y, 2);
}
}
// TPC command for scheduled PUCCH 2 bits
dci->tpc = srsran_bit_pack(&y, 2);
// PUCCH resource indicator 3 bits
dci->pucch_resource = srsran_bit_pack(&y, 3);
// PDSCH-to-HARQ_feedback timing indicator 0, 1, 2, or 3 bits
dci->harq_feedback = srsran_bit_pack(&y, (int)SRSRAN_CEIL_LOG2(cfg->nof_dl_to_ul_ack));
// Antenna port(s) 4, 5, or 6 bits
dci->ports = srsran_bit_pack(&y, dci_nr_dl_ports_size(cfg));
// Transmission configuration indication 0 or 3 bits
if (cfg->pdsch_tci) {
dci->tci = srsran_bit_pack(&y, 3);
}
// SRS request 2 or 3 bits
dci->srs_request = srsran_bit_pack(&y, cfg->enable_sul ? 3 : 2);
// CBG transmission information (CBGTI) 0, 2, 4, 6, or 8 bits
dci->cbg_info = srsran_bit_pack(&y, cfg->pdsch_nof_cbg);
// CBG flushing out information (CBGFI) 0 or 1 bit
if (cfg->pdsch_cbg_flush) {
dci->cbg_flush = srsran_bit_pack(&y, 1);
}
// DMRS sequence initialization 1 bit
dci->dmrs_id = srsran_bit_pack(&y, 1);
uint32_t nof_unpacked_bits = (uint32_t)(y - msg->payload);
if (nof_unpacked_bits != nof_bits) {
ERROR("Unpacked bits read (%d) do NOT match payload size (%d)", nof_unpacked_bits, nof_bits);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static uint32_t
dci_nr_format_1_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
const srsran_dci_cfg_nr_t* cfg = &q->cfg;
// Carrier indicator 0 or 3 bits
if (cfg->carrier_indicator_size > 0) {
len = srsran_print_check(str, str_len, len, "cc=%d ", dci->cc_id);
}
// Bandwidth part indicator 0, 1 or 2 bits
if (dci_nr_bwp_id_size(cfg->nof_dl_bwp) > 0) {
len = srsran_print_check(str, str_len, len, "bwp=%d ", dci->bwp_id);
}
// Frequency domain resource assignment
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// Time domain resource assignment 0, 1, 2, 3, or 4 bits
if (cfg->nof_dl_time_res > 0) {
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
}
// VRB-to-PRB mapping 0 or 1
if (cfg->pdsch_alloc_type != srsran_resource_alloc_type0 && cfg->pdsch_inter_prb_to_prb) {
len = srsran_print_check(str, str_len, len, "vrb_to_prb_map=%d ", dci->vrb_to_prb_mapping);
}
// PRB bundling size indicator 0 or 1 bits
// ... not implemented
// Rate matching indicator 0, 1, or 2 bits
if (cfg->pdsch_rm_pattern1) {
len = srsran_print_check(str, str_len, len, "rm_pattern1=%d ", dci->rm_pattern1);
}
if (cfg->pdsch_rm_pattern2) {
len = srsran_print_check(str, str_len, len, "rm_pattern2=%d ", dci->rm_pattern2);
}
// ZP CSI-RS trigger - 0, 1, or 2 bits
if (SRSRAN_CEIL_LOG2(cfg->nof_aperiodic_zp + 1) > 0) {
len = srsran_print_check(str, str_len, len, "zp_csi_rs_id=%d ", dci->zp_csi_rs_id);
}
// For transport block 1:
// Modulation and coding scheme 5 bits
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// New data indicator 1 bit
len = srsran_print_check(str, str_len, len, "ndi=%d ", dci->ndi);
// Redundancy version 2 bits
len = srsran_print_check(str, str_len, len, "rv=%d ", dci->rv);
// For transport block 2:
if (cfg->pdsch_2cw) {
// Modulation and coding scheme 5 bits
len = srsran_print_check(str, str_len, len, "mcs2=%d ", dci->mcs2);
// New data indicator 1 bit
len = srsran_print_check(str, str_len, len, "ndi2=%d ", dci->ndi2);
// Redundancy version 2 bits
len = srsran_print_check(str, str_len, len, "rv2=%d ", dci->rv2);
}
// HARQ process number 4 bits
len = srsran_print_check(str, str_len, len, "harq_id=%d ", dci->pid);
// Downlink assignment index (dynamic HARQ-ACK codebook only)
if (cfg->harq_ack_codebok == srsran_pdsch_harq_ack_codebook_dynamic) {
len = srsran_print_check(str, str_len, len, "dai=%d ", dci->dai);
}
// TPC command for scheduled PUCCH 2 bits
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
// PDSCH-to-HARQ_feedback timing indicator 0, 1, 2, or 3 bits
if (cfg->nof_dl_to_ul_ack > 0) {
len = srsran_print_check(str, str_len, len, "harq_feedback=%d ", dci->harq_feedback);
}
// Antenna port(s) 4, 5, or 6 bits
if (dci_nr_dl_ports_size(cfg) > 0) {
len = srsran_print_check(str, str_len, len, "ports=%d ", dci->ports);
}
// Transmission configuration indication 0 or 3 bits
if (cfg->pdsch_tci) {
len = srsran_print_check(str, str_len, len, "tci=%d ", dci->tci);
}
// SRS request 2 or 3 bits
len = srsran_print_check(str, str_len, len, "srs_request=%d ", dci->srs_request);
// CBG transmission information (CBGTI) 0, 2, 4, 6, or 8 bits
if (cfg->pdsch_nof_cbg > 0) {
len = srsran_print_check(str, str_len, len, "cbg_info=%d ", dci->cbg_info);
}
// CBG flushing out information (CBGFI) 0 or 1 bit
if (cfg->pdsch_cbg_flush > 0) {
len = srsran_print_check(str, str_len, len, "cbg_flush=%d ", dci->cbg_flush);
}
// DMRS sequence initialization 1 bit
len = srsran_print_check(str, str_len, len, "dmrs_id=%d ", dci->dmrs_id);
return len;
}
int srsran_dci_nr_set_cfg(srsran_dci_nr_t* q, const srsran_dci_cfg_nr_t* cfg)
{
if (q == NULL || cfg == NULL) {
return SRSRAN_ERROR;
}
// Reset current setup
SRSRAN_MEM_ZERO(q, srsran_dci_nr_t, 1);
// Copy configuration
q->cfg = *cfg;
// Step 0
// - Determine DCI format 0_0 monitored in a common search space according to clause 7.3.1.1.1 where N_UL_BWP_RB is
// given by the size of the initial UL bandwidth part.
uint32_t size_dci_0_0_common = dci_nr_format_0_0_sizeof(cfg->bwp_ul_initial_bw, cfg);
// - Determine DCI format 1_0 monitored in a common search space according to clause 7.3.1.2.1 where N_DL_BWP_RB given
// by:
// - the size of CORESET 0 if CORESET 0 is configured for the cell; and
// - the size of initial DL bandwidth part if CORESET 0 is not configured for the cell.
uint32_t size_dci_1_0_common = dci_nr_format_1_0_sizeof(cfg->bwp_dl_initial_bw, srsran_rnti_type_c);
if (cfg->coreset0_bw != 0) {
size_dci_1_0_common = dci_nr_format_1_0_sizeof(cfg->coreset0_bw, srsran_rnti_type_c);
}
// - If DCI format 0_0 is monitored in common search space and if the number of information bits in the DCI format 0_0
// prior to padding is less than the payload size of the DCI format 1_0 monitored in common search space for
// scheduling the same serving cell, a number of zero padding bits are generated for the DCI format 0_0 until the
// payload size equals that of the DCI format 1_0.
if (cfg->monitor_common_0_0 && size_dci_0_0_common < size_dci_1_0_common) {
q->dci_0_0_common_padd = size_dci_1_0_common - size_dci_0_0_common;
} else {
q->dci_0_0_common_padd = 0;
}
// - If DCI format 0_0 is monitored in common search space and if the number of information bits in the DCI format 0_0
// prior to truncation is larger than the payload size of the DCI format 1_0 monitored in common search space for
// scheduling the same serving cell, the bitwidth of the frequency domain resource assignment field in the DCI format
// 0_0 is reduced by truncating the first few most significant bits such that the size of DCI format 0_0 equals the
// size of the DCI format 1_0.
if (cfg->monitor_common_0_0 && size_dci_0_0_common > size_dci_1_0_common) {
q->dci_0_0_common_trunc = size_dci_0_0_common - size_dci_1_0_common;
} else {
q->dci_0_0_common_trunc = 0;
}
q->dci_0_0_and_1_0_common_size = SRSRAN_MAX(size_dci_1_0_common, DCI_NR_MIN_SIZE);
// Step 1
// - Determine DCI format 0_0 monitored in a UE-specific search space according to clause 7.3.1.1.1 where N_UL_BWP_RB
// is the size of the active UL bandwidth part.
uint32_t size_dci_0_0_ue = dci_nr_format_0_0_sizeof(cfg->bwp_ul_active_bw, cfg);
// - Determine DCI format 1_0 monitored in a UE-specific search space according to clause 7.3.1.2.1 where N_DL_BWP_RB
// is the size of the active DL bandwidth part.
uint32_t size_dci_1_0_ue = dci_nr_format_1_0_sizeof(cfg->bwp_dl_active_bw, srsran_rnti_type_c);
// - For a UE configured with supplementaryUplink in ServingCellConfig in a cell, if PUSCH is configured to be
// transmitted on both the SUL and the non-SUL of the cell and if the number of information bits in DCI format 0_0 in
// UE-specific search space for the SUL is not equal to the number of information bits in DCI format 0_0 in
// UE-specific search space for the non-SUL, a number of zero padding bits are generated for the smaller DCI format
// 0_0 until the payload size equals that of the larger DCI format 0_0.
// ... Not implemented
// - If DCI format 0_0 is monitored in UE-specific search space and if the number of information bits in the DCI
// format 0_0 prior to padding is less than the payload size of the DCI format 1_0 monitored in UE-specific search
// space for scheduling the same serving cell, a number of zero padding bits are generated for the DCI format 0_0
// until the payload size equals that of the DCI format 1_0.
if (cfg->monitor_0_0_and_1_0 && size_dci_0_0_ue < size_dci_1_0_ue) {
q->dci_0_0_ue_padd = size_dci_1_0_ue - size_dci_0_0_ue;
}
// - If DCI format 1_0 is monitored in UE-specific search space and if the number of information bits in the DCI
// format 1_0 prior to padding is less than the payload size of the DCI format 0_0 monitored in UE-specific search
// space for scheduling the same serving cell, zeros shall be appended to the DCI format 1_0 until the payload size
// equals that of the DCI format 0_0
if (cfg->monitor_0_0_and_1_0 && size_dci_1_0_ue < size_dci_0_0_ue) {
q->dci_1_0_ue_padd = size_dci_0_0_ue - size_dci_1_0_ue;
}
q->dci_0_0_and_1_0_ue_size = SRSRAN_MAX(SRSRAN_MAX(size_dci_0_0_ue, size_dci_1_0_ue), DCI_NR_MIN_SIZE);
// Step 2
// For a UE configured with supplementaryUplink in ServingCellConfig in a cell, if PUSCH is configured to be
// transmitted on both the SUL and the non-SUL of the cell and if the number of information bits in format 0_1 for
// the SUL is not equal to the number of information bits in format 0_1 for the non-SUL, zeros shall be appended
// to smaller format 0_1 until the payload size equals that of the larger format 0_1.
// ... Not implemented
uint32_t size_dci_0_1 = dci_nr_format_0_1_sizeof(cfg, srsran_rnti_type_c);
uint32_t size_dci_1_1 = dci_nr_format_1_1_sizeof(cfg, srsran_rnti_type_c);
if (size_dci_0_1 == 0 || size_dci_1_1 == 0) {
return SRSRAN_ERROR;
}
// If the size of DCI format 0_1 monitored in a UE-specific search space equals that of a DCI format 0_0/1_0
// monitored in another UE-specific search space, one bit of zero padding shall be appended to DCI format 0_1.
if (size_dci_0_1 == q->dci_0_0_and_1_0_ue_size) {
q->dci_0_1_padd++;
}
// If the size of DCI format 1_1 monitored in a UE-specific search space equals that of a DCI format 0_0/1_0
// monitored in another UE-specific search space, one bit of zero padding shall be appended to DCI format 1_1.
if (size_dci_1_1 == q->dci_0_0_and_1_0_ue_size) {
q->dci_1_1_padd++;
}
q->dci_0_1_size = size_dci_0_1 + q->dci_0_1_padd;
q->dci_1_1_size = size_dci_1_1 + q->dci_1_1_padd;
// Step 3
// If both of the following conditions are fulfilled the size alignment procedure is complete:
// - the total number of different DCI sizes configured to monitor is no more than 4 for the cell
// - the total number of different DCI sizes with C-RNTI configured to monitor is no more than 3 for the cell
// ... Current code is compatible with only possible sizes!
return SRSRAN_SUCCESS;
}
uint32_t srsran_dci_nr_size(const srsran_dci_nr_t* q, srsran_search_space_type_t ss_type, srsran_dci_format_nr_t format)
{
// Check input
if (q == NULL) {
return 0;
}
// For common search space, only formats 0_0 and 1_0
if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)) {
return q->dci_0_0_and_1_0_common_size;
}
// DCI formats 0_0 and 1_0 in UE-specific
if (format == srsran_dci_format_nr_0_0 || format == srsran_dci_format_nr_1_0) {
return q->dci_0_0_and_1_0_ue_size;
}
// DCI format 0_1 in UE-specific
if (format == srsran_dci_format_nr_0_1) {
return q->dci_0_1_size;
}
// DCI format 1_1 in UE-specific
if (format == srsran_dci_format_nr_1_1) {
return q->dci_1_1_size;
}
// RAR packed MSG3 DCI
if (format == srsran_dci_format_nr_rar) {
return dci_nr_rar_sizeof();
}
// Not implemented
return 0;
}
bool srsran_dci_nr_valid_direction(const srsran_dci_msg_nr_t* dci)
{
// Check pointer
if (dci == NULL) {
return false;
}
// UL direction
uint32_t expected_direction = 0;
// Set DL direction if is DL grant
if (dci->ctx.format == srsran_dci_format_nr_1_0 || dci->ctx.format == srsran_dci_format_nr_1_1) {
expected_direction = 1;
}
// The format bit is only present for these RNTI
if (dci->ctx.rnti_type == srsran_rnti_type_c || dci->ctx.rnti_type == srsran_rnti_type_tc) {
return dci->payload[0] == expected_direction;
}
// For other RNTI types, assume always DL on 1_0
return (dci->ctx.format == srsran_dci_format_nr_1_0);
}
int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
if (q == NULL || dci == NULL || msg == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
msg->ctx = dci->ctx;
// Pack DCI
switch (msg->ctx.format) {
case srsran_dci_format_nr_1_0:
return dci_nr_format_1_0_pack(q, dci, msg);
case srsran_dci_format_nr_1_1:
return dci_nr_format_1_1_pack(q, dci, msg);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
return SRSRAN_ERROR;
}
int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci)
{
if (q == NULL || dci == NULL || msg == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
dci->ctx = msg->ctx;
dci->coreset0_bw = q->cfg.coreset0_bw;
// Pack DCI
switch (msg->ctx.format) {
case srsran_dci_format_nr_1_0:
return dci_nr_format_1_0_unpack(q, msg, dci);
case srsran_dci_format_nr_1_1:
return dci_nr_format_1_1_unpack(q, msg, dci);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
return SRSRAN_ERROR;
}
int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
if (msg == NULL || dci == NULL) {
return SRSRAN_ERROR;
}
if (dci->ctx.format != srsran_dci_format_nr_rar && q == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
msg->ctx = dci->ctx;
// Pack DCI
switch (msg->ctx.format) {
case srsran_dci_format_nr_0_0:
return dci_nr_format_0_0_pack(q, dci, msg);
case srsran_dci_format_nr_0_1:
return dci_nr_format_0_1_pack(q, dci, msg);
case srsran_dci_format_nr_rar:
return dci_nr_rar_pack(dci, msg);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
return SRSRAN_ERROR;
}
int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
if (msg == NULL || dci == NULL) {
return SRSRAN_ERROR;
}
if (msg->ctx.format != srsran_dci_format_nr_rar && q == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
dci->ctx = msg->ctx;
// Pack DCI
switch (msg->ctx.format) {
case srsran_dci_format_nr_0_0:
return dci_nr_format_0_0_unpack(q, msg, dci);
case srsran_dci_format_nr_0_1:
return dci_nr_format_0_1_unpack(q, msg, dci);
case srsran_dci_format_nr_rar:
return dci_nr_rar_unpack(msg, dci);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
return SRSRAN_ERROR;
}
uint32_t srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_len)
{
if (ctx == NULL || str == NULL) {
return 0;
}
uint32_t len = 0;
// Print base
len = srsran_print_check(str,
str_len,
len,
"%s-rnti=0x%04x dci=%s ss=%s ",
srsran_rnti_type_str_short(ctx->rnti_type),
ctx->rnti,
srsran_dci_format_nr_string(ctx->format),
srsran_ss_type_str(ctx->ss_type));
if (ctx->format != srsran_dci_format_nr_rar) {
len = srsran_print_check(str, str_len, len, "L=%d cce=%d ", ctx->location.L, ctx->location.ncce);
}
return len;
}
uint32_t srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
if (q == NULL || dci == NULL || str == NULL) {
return 0;
}
uint32_t len = 0;
len += srsran_dci_ctx_to_str(&dci->ctx, &str[len], str_len - len);
// Pack DCI
switch (dci->ctx.format) {
case srsran_dci_format_nr_0_0:
len += dci_nr_format_0_0_to_str(dci, &str[len], str_len - len);
break;
case srsran_dci_format_nr_0_1:
len += dci_nr_format_0_1_to_str(q, dci, &str[len], str_len - len);
break;
case srsran_dci_format_nr_rar:
len += dci_nr_rar_to_str(dci, &str[len], str_len - len);
break;
default:
len = srsran_print_check(str, str_len, len, "<invalid ul dci> ");
break;
}
return len;
}
uint32_t srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
if (q == NULL || dci == NULL || str == NULL) {
return SRSRAN_ERROR;
}
uint32_t len = 0;
len += srsran_dci_ctx_to_str(&dci->ctx, &str[len], str_len - len);
// Pack DCI
switch (dci->ctx.format) {
case srsran_dci_format_nr_1_0:
len += dci_nr_format_1_0_to_str(dci, &str[len], str_len - len);
break;
case srsran_dci_format_nr_1_1:
len += dci_nr_format_1_1_to_str(q, dci, &str[len], str_len - len);
break;
default:
len = srsran_print_check(str, str_len, len, "<invalid dl dci> ");
break;
}
return len;
}