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

1783 lines
52 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 <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "srsran/phy/common/phy_common.h"
#include "srsran/phy/phch/dci.h"
#include "srsran/phy/utils/bit.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
#include "srsran/srsran.h"
#define IS_TDD (cell->frame_type == SRSRAN_TDD)
#define IS_TDD_CFG0 (IS_TDD && (sf->tdd_config.sf_config == 0))
#define HARQ_PID_LEN ((IS_TDD | IS_TDD_CFG0) ? 4 : 3)
/* Unpack RAR UL dci as defined in Section 6.2 of 36.213 */
void srsran_dci_rar_unpack(uint8_t payload[SRSRAN_RAR_GRANT_LEN], srsran_dci_rar_grant_t* rar)
{
uint8_t* ptr = payload;
rar->hopping_flag = srsran_bit_pack(&ptr, 1) ? true : false;
rar->rba = srsran_bit_pack(&ptr, 10);
rar->trunc_mcs = srsran_bit_pack(&ptr, 4);
rar->tpc_pusch = srsran_bit_pack(&ptr, 3);
rar->ul_delay = srsran_bit_pack(&ptr, 1) ? true : false;
rar->cqi_request = srsran_bit_pack(&ptr, 1) ? true : false;
}
/* Pack RAR UL dci as defined in Section 6.2 of 36.213 */
void srsran_dci_rar_pack(srsran_dci_rar_grant_t* rar, uint8_t payload[SRSRAN_RAR_GRANT_LEN])
{
uint8_t* ptr = payload;
srsran_bit_unpack(rar->hopping_flag ? 1 : 0, &ptr, 1);
srsran_bit_unpack(rar->rba, &ptr, 10);
srsran_bit_unpack(rar->trunc_mcs, &ptr, 4);
srsran_bit_unpack(rar->tpc_pusch, &ptr, 3);
srsran_bit_unpack(rar->ul_delay ? 1 : 0, &ptr, 1);
srsran_bit_unpack(rar->cqi_request ? 1 : 0, &ptr, 1);
}
/* Creates an equivalent DCI UL grant from the random access respone message
*/
int srsran_dci_rar_to_ul_dci(srsran_cell_t* cell, srsran_dci_rar_grant_t* rar, srsran_dci_ul_t* dci_ul)
{
bzero(dci_ul, sizeof(srsran_dci_ul_t));
if (!rar->hopping_flag) {
dci_ul->freq_hop_fl = SRSRAN_RA_PUSCH_HOP_DISABLED;
} else {
ERROR("TODO: Frequency hopping in RAR not implemented");
dci_ul->freq_hop_fl = 1;
}
uint32_t riv = rar->rba;
// Truncate resource block assignment
uint32_t b = 0;
if (cell->nof_prb <= 44) {
b = (uint32_t)(ceilf(log2((float)cell->nof_prb * (cell->nof_prb + 1) / 2)));
riv = riv & ((1 << (b + 1)) - 1);
}
dci_ul->type2_alloc.riv = riv;
dci_ul->tb.mcs_idx = rar->trunc_mcs;
dci_ul->tb.rv = -1;
dci_ul->dai = 3;
return SRSRAN_SUCCESS;
}
static uint32_t riv_nbits(uint32_t nof_prb)
{
return (uint32_t)ceilf(log2f((float)nof_prb * ((float)nof_prb + 1) / 2));
}
const uint32_t ambiguous_sizes[10] = {12, 14, 16, 20, 24, 26, 32, 40, 44, 56};
static bool is_ambiguous_size(uint32_t size)
{
int i;
for (i = 0; i < 10; i++) {
if (size == ambiguous_sizes[i]) {
return true;
}
}
return false;
}
/**********************************
* PAYLOAD sizeof functions
* ********************************/
static uint32_t dci_format0_sizeof_(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = 0;
/* Carrier indicator 0 or 3 bits */
n += (cfg->cif_enabled) ? 3 : 0;
/* Flag for format0/format1A differentiation 1 bit */
n += 1;
/* Frequency hopping flag 1 bit */
n += 1;
/* Resource block assignment and hopping resource allocation */
n += riv_nbits(cell->nof_prb);
/* Modulation and coding scheme and redundancy version 5 bits */
n += 5;
/* New data indicator 1 bit */
n += 1;
/* TPC command for scheduled PUSCH 2 bits */
n += 2;
/* Cyclic shift for DM RS and OCC index 3 bits */
n += 3;
/* Downlink Assignment Index (DAI) or UL Index 2 bits (TDD) */
n += ((IS_TDD | IS_TDD_CFG0) ? 2 : 0);
/* CSI request 1 or 2 bits */
n += (cfg->multiple_csi_request_enabled && !cfg->is_not_ue_ss) ? 2 : 1;
/* SRS request 0 or 1 bit */
n += (cfg->srs_request_enabled && !cfg->is_not_ue_ss) ? 1 : 0;
/* Resource allocation type 1 bit (N^UL_RB ≤ N^DL_RB)
* This is a release10 field only, but it is backwards compatible to release 8 because a padding bit will be added.
*/
n++;
return n;
}
static uint32_t dci_format1A_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = 0;
/* Carrier indicator 0 or 3 bits */
n += (cfg->cif_enabled) ? 3 : 0;
/* Flag for format0/format1A differentiation 1 bit */
n += 1;
/* Localized/Distributed VRB assignment flag 1 bit */
n += 1;
/* Resource block assignment */
n += riv_nbits(cell->nof_prb);
/* Modulation and coding scheme and redundancy version 5 bits */
n += 5;
/* HARQ process number 3 bits (FDD) , 4 bits (TDD) */
n += HARQ_PID_LEN;
/* New data indicator 1 bit */
n += 1;
/* Redundancy version 2 bits */
n += 2;
/* TPC command for PUCCH 2 bits */
n += 2;
/* Downlink Assignment Index 2 bits (TDD) */
n += (IS_TDD ? 2 : 0);
/* SRS request 0 or 1 bit */
n += (cfg->srs_request_enabled ? 1 : 0);
while (n < dci_format0_sizeof_(cell, sf, cfg)) {
n++;
}
if (is_ambiguous_size(n)) {
n++;
}
return n;
}
static uint32_t dci_format0_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = dci_format0_sizeof_(cell, sf, cfg);
while (n < dci_format1A_sizeof(cell, sf, cfg)) {
n++;
}
return n;
}
static uint32_t dci_format1_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srsran_ra_type0_P(cell->nof_prb)) + 5 + HARQ_PID_LEN + 1 + 2 + 2 +
(cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0);
if (cell->nof_prb > 10) {
n++;
}
while (n == dci_format0_sizeof(cell, sf, cfg) || n == dci_format1A_sizeof(cell, sf, cfg) || is_ambiguous_size(n)) {
n++;
}
return n;
}
static uint32_t dci_format1C_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n_vrb_dl_gap1 = srsran_ra_type2_n_vrb_dl(cell->nof_prb, true);
uint32_t n_step = srsran_ra_type2_n_rb_step(cell->nof_prb);
uint32_t n = riv_nbits((uint32_t)n_vrb_dl_gap1 / n_step) + 5;
if (cell->nof_prb >= 50) {
n++;
}
return n;
}
// Number of TPMI bits
static uint32_t tpmi_bits(uint32_t nof_ports)
{
if (nof_ports <= 2) {
return 2;
} else {
return 4;
}
}
static uint32_t dci_format1B_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = 0;
/* Carrier indicator 0 or 3 bits */
n += (cfg->cif_enabled) ? 3 : 0;
/* Localized/Distributed VRB assignment flag 1 bit */
n += 1;
/* Resource block assignment */
n += riv_nbits(cell->nof_prb);
/* Modulation and coding scheme and redundancy version 5 bits */
n += 5;
/* HARQ process number 3 bits (FDD) , 4 bits (TDD) */
n += HARQ_PID_LEN;
/* New data indicator 1 bit */
n += 1;
/* Redundancy version 2 bits */
n += 2;
/* TPC command for PUCCH 2 bits */
n += 2;
/* Downlink Assignment Index 2 bits (TDD) */
n += (IS_TDD ? 2 : 0);
/* TPMI information for precoding number of bits as specified in Table 5.3.3.1.3A-1 */
n += tpmi_bits(cell->nof_ports);
/* PMI confirmation for precoding 1 bit as specified in Table 5.3.3.1.3A-2 */
n += 1;
while (n < dci_format0_sizeof_(cell, sf, cfg)) {
n++;
}
while (is_ambiguous_size(n)) {
n++;
}
return n;
}
static uint32_t dci_format1D_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
// same size as format1B
return dci_format1B_sizeof(cell, sf, cfg);
}
// Number of bits for precoding information
static uint32_t precoding_bits_f2(uint32_t nof_ports)
{
if (nof_ports <= 2) {
return 3;
} else {
return 6;
}
}
static uint32_t dci_format2_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srsran_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 +
2 * (5 + 1 + 2) + precoding_bits_f2(cell->nof_ports) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0);
if (cell->nof_prb > 10) {
n++;
}
while (is_ambiguous_size(n)) {
n++;
}
return n;
}
// Number of bits for precoding information
static uint32_t precoding_bits_f2a(uint32_t nof_ports)
{
if (nof_ports <= 2) {
return 0;
} else {
return 2;
}
}
static uint32_t dci_format2A_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srsran_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 +
2 * (5 + 1 + 2) + precoding_bits_f2a(cell->nof_ports) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0);
if (cell->nof_prb > 10) {
n++;
}
while (is_ambiguous_size(n)) {
n++;
}
return n;
}
static uint32_t dci_format2B_sizeof(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* cfg)
{
uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srsran_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 +
2 * (5 + 1 + 2) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0);
if (cell->nof_prb > 10) {
n++;
}
while (is_ambiguous_size(n)) {
n++;
}
return n;
}
uint32_t srsran_dci_format_sizeof(const srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_format_t format)
{
srsran_dl_sf_cfg_t _sf;
if (sf == NULL) {
ZERO_OBJECT(_sf);
sf = &_sf;
}
srsran_dci_cfg_t _cfg;
if (cfg == NULL) {
ZERO_OBJECT(_cfg);
cfg = &_cfg;
}
switch (format) {
case SRSRAN_DCI_FORMAT0:
return dci_format0_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT1:
return dci_format1_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT1A:
return dci_format1A_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT1C:
return dci_format1C_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT1B:
return dci_format1B_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT1D:
return dci_format1D_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT2:
return dci_format2_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT2A:
return dci_format2A_sizeof(cell, sf, cfg);
case SRSRAN_DCI_FORMAT2B:
return dci_format2B_sizeof(cell, sf, cfg);
/*
case SRSRAN_DCI_FORMAT3:
return dci_format3_sizeof(nof_prb);
case SRSRAN_DCI_FORMAT3A:
return dci_format3A_sizeof(nof_prb);
*/
default:
printf("Error computing DCI bits: Unknown format %d\n", format);
return 0;
}
}
/**********************************
* DCI Resource Allocation functions
* ********************************/
/* Packs DCI format 0 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
static int dci_format0_pack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_ul_t* dci,
srsran_dci_msg_t* msg)
{
/* pack bits */
uint8_t* y = msg->payload;
uint32_t n_ul_hop;
if (dci->cif_present) {
srsran_bit_unpack(dci->cif, &y, 3);
}
*y++ = 0; // format differentiation
if (dci->freq_hop_fl == SRSRAN_RA_PUSCH_HOP_DISABLED) { // frequency hopping
*y++ = 0;
n_ul_hop = 0;
} else {
*y++ = 1;
if (cell->nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
*y++ = dci->freq_hop_fl & 1;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
*y++ = (dci->freq_hop_fl & 2) >> 1;
*y++ = dci->freq_hop_fl & 1;
}
}
/* pack RIV according to 8.1 of 36.213 */
uint32_t riv = dci->type2_alloc.riv;
srsran_bit_unpack(riv, &y, riv_nbits(cell->nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */
srsran_bit_unpack(dci->tb.mcs_idx, &y, 5);
*y++ = dci->tb.ndi;
// TCP command for PUSCH
srsran_bit_unpack(dci->tpc_pusch, &y, 2);
// DM RS not implemented
srsran_bit_unpack(dci->n_dmrs, &y, 3);
// CSI request 1 or 2 bits as defined in section 7.2.1 of 36.213. The 2-bit field applies to UEs that are configured
// with more than one DL cell and when the corresponding DCI format is mapped onto the UE specific search space given
// by the C-RNTI as defined in 36.213; otherwise the 1-bit field applies
if (cfg->multiple_csi_request_enabled && !cfg->is_not_ue_ss) {
*y++ = dci->cqi_request;
*y++ = 0;
} else {
*y++ = dci->cqi_request;
}
// SRS request 0 or 1 bit. This field can only be present in DCI formats scheduling PUSCH which are mapped onto
// the UE specific search space given by the C-RNTI as defined in 36.213. The interpretation of this field is provided
// in section 8.2 of 36.213
if (cfg->srs_request_enabled && !cfg->is_not_ue_ss) {
*y++ = dci->srs_request && dci->srs_request_present;
}
// Padding with zeros
uint32_t n = srsran_dci_format_sizeof(cell, sf, cfg, SRSRAN_DCI_FORMAT0);
while (y - msg->payload < n) {
*y++ = 0;
}
msg->nof_bits = (y - msg->payload);
return SRSRAN_SUCCESS;
}
/* Unpacks DCI format 0 data and store result in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
static int dci_format0_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_ul_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
uint32_t n_ul_hop;
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
if (*y++ != 0) {
INFO("DCI message is Format1A");
return SRSRAN_ERROR;
}
// Update DCI format
msg->format = SRSRAN_DCI_FORMAT0;
if (*y++ == 0) {
dci->freq_hop_fl = SRSRAN_RA_PUSCH_HOP_DISABLED;
n_ul_hop = 0;
} else {
if (cell->nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
dci->freq_hop_fl = *y++;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
dci->freq_hop_fl = y[0] << 1 | y[1];
y += 2;
}
}
/* unpack RIV according to 8.1 of 36.213 */
uint32_t riv = srsran_bit_pack(&y, riv_nbits(cell->nof_prb) - n_ul_hop);
dci->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */
dci->tb.mcs_idx = srsran_bit_pack(&y, 5);
dci->tb.ndi = *y++ ? true : false;
// TPC command for scheduled PUSCH
dci->tpc_pusch = srsran_bit_pack(&y, 2);
// Cyclic shift for DMRS
dci->n_dmrs = srsran_bit_pack(&y, 3);
// TDD fields
if (IS_TDD_CFG0) {
dci->ul_idx = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
} else if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
// CQI request
if (cfg->multiple_csi_request_enabled && !cfg->is_not_ue_ss) {
dci->multiple_csi_request_present = true;
dci->multiple_csi_request = srsran_bit_pack(&y, 2);
} else {
dci->cqi_request = *y++ ? true : false;
}
// SRS request
if (cfg->srs_request_enabled && !cfg->is_not_ue_ss) {
dci->srs_request_present = true;
dci->srs_request = *y++ ? true : false;
}
if (cfg->ra_format_enabled) {
dci->ra_type_present = true;
dci->ra_type = *y++ ? true : false;
}
return SRSRAN_SUCCESS;
}
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.2
*
* TODO: TPC commands
*/
static int dci_format1_pack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_dl_t* dci,
srsran_dci_msg_t* msg)
{
uint32_t nof_prb = cell->nof_prb;
/* pack bits */
uint8_t* y = msg->payload;
if (dci->cif_present) {
srsran_bit_unpack(dci->cif, &y, 3);
}
if (nof_prb > 10) {
*y++ = dci->alloc_type;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = srsran_ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t)ceilf((float)nof_prb / P);
switch (dci->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
srsran_bit_unpack((uint32_t)dci->type0_alloc.rbg_bitmask, &y, alloc_size);
break;
case SRSRAN_RA_ALLOC_TYPE1:
srsran_bit_unpack((uint32_t)dci->type1_alloc.rbg_subset, &y, (int)ceilf(log2f(P)));
*y++ = dci->type1_alloc.shift ? 1 : 0;
srsran_bit_unpack((uint32_t)dci->type1_alloc.vrb_bitmask, &y, alloc_size - (int)ceilf(log2f(P)) - 1);
break;
default:
ERROR("Format 1 accepts type0 or type1 resource allocation only");
return SRSRAN_ERROR;
}
/* pack MCS */
srsran_bit_unpack(dci->tb[0].mcs_idx, &y, 5);
/* harq process number */
srsran_bit_unpack(dci->pid, &y, HARQ_PID_LEN);
*y++ = dci->tb[0].ndi;
// rv version
srsran_bit_unpack(dci->tb[0].rv, &y, 2);
// TCP command for PUCCH
srsran_bit_unpack(dci->tpc_pucch, &y, 2);
uint32_t n = srsran_dci_format_sizeof(cell, sf, cfg, SRSRAN_DCI_FORMAT1);
while (y - msg->payload < n) {
*y++ = 0;
}
msg->nof_bits = (y - msg->payload);
if (msg->nof_bits != dci_format1_sizeof(cell, sf, cfg)) {
ERROR("Invalid message length for format 1 (Cross scheduling %s)", dci->cif_present ? "enabled" : "disabled");
}
return SRSRAN_SUCCESS;
}
static int dci_format1_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
/* Make sure it's a SRSRAN_DCI_FORMAT1 message */
uint32_t msg_len = srsran_dci_format_sizeof(cell, sf, cfg, SRSRAN_DCI_FORMAT1);
if (msg->nof_bits != msg_len) {
ERROR("Invalid message length (%d!=%d) for format 1", msg->nof_bits, msg_len);
return SRSRAN_ERROR;
}
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
if (cell->nof_prb > 10) {
dci->alloc_type = *y++;
} else {
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE0;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = srsran_ra_type0_P(cell->nof_prb);
uint32_t alloc_size = (uint32_t)ceilf((float)cell->nof_prb / P);
switch (dci->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
dci->type0_alloc.rbg_bitmask = srsran_bit_pack(&y, alloc_size);
break;
case SRSRAN_RA_ALLOC_TYPE1:
dci->type1_alloc.rbg_subset = srsran_bit_pack(&y, (int)ceilf(log2f(P)));
dci->type1_alloc.shift = *y++ ? true : false;
dci->type1_alloc.vrb_bitmask = srsran_bit_pack(&y, alloc_size - (int)ceilf(log2f(P)) - 1);
break;
default:
ERROR("Format 1 accepts type0 or type1 resource allocation only");
return SRSRAN_ERROR;
}
/* unpack MCS according to 7.1.7 of 36.213 */
dci->tb[0].mcs_idx = srsran_bit_pack(&y, 5);
/* harq process number */
dci->pid = srsran_bit_pack(&y, HARQ_PID_LEN);
dci->tb[0].ndi = *y++ ? true : false;
// rv version
dci->tb[0].rv = srsran_bit_pack(&y, 2);
// TPC PUCCH
dci->tpc_pucch = srsran_bit_pack(&y, 2);
// TDD
if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
return SRSRAN_SUCCESS;
}
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
* TODO: TPC commands
*/
static int dci_format1As_pack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_dl_t* dci,
srsran_dci_msg_t* msg)
{
uint32_t nof_prb = cell->nof_prb;
/* pack bits */
uint8_t* y = msg->payload;
if (dci->cif_present) {
srsran_bit_unpack(dci->cif, &y, 3);
}
*y++ = 1; // format differentiation
// random access procedure initiated by a PDCCH order
if (dci->is_pdcch_order) {
*y++ = 0; // localized or distributed VRB assignment is always 0 for PDCCH order
// RIV values all set to 1 for PDCCH order
int nof_bits = riv_nbits(cell->nof_prb);
int i = 0;
while (i < nof_bits) {
*y++ = 1;
i++;
}
srsran_bit_unpack(dci->preamble_idx, &y, 6); // preamble index
srsran_bit_unpack(dci->prach_mask_idx, &y, 4); // PRACH mask index
} else {
if (dci->alloc_type != SRSRAN_RA_ALLOC_TYPE2) {
ERROR("Format 1A accepts type2 resource allocation only");
return SRSRAN_ERROR;
}
*y++ = dci->type2_alloc.mode; // localized or distributed VRB assignment
/* pack RIV according to 7.1.6.3 of 36.213 */
uint32_t riv = dci->type2_alloc.riv;
uint32_t nb_gap = 0;
if (SRSRAN_RNTI_ISUSER(dci->rnti) && dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST && nof_prb >= 50) {
nb_gap = 1;
*y++ = dci->type2_alloc.n_gap;
}
srsran_bit_unpack(riv, &y, riv_nbits(nof_prb) - nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
srsran_bit_unpack(dci->tb[0].mcs_idx, &y, 5);
srsran_bit_unpack(dci->pid, &y, HARQ_PID_LEN);
if (!SRSRAN_RNTI_ISUSER(dci->rnti)) {
if (nof_prb >= 50 && dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST) {
*y++ = dci->type2_alloc.n_gap;
} else {
y++; // bit reserved
}
} else {
*y++ = dci->tb[0].ndi;
}
// rv version
srsran_bit_unpack(dci->tb[0].rv, &y, 2);
if (SRSRAN_RNTI_ISUSER(dci->rnti)) {
// TPC not implemented
*y++ = 0;
*y++ = 0;
} else {
y++; // MSB of TPC is reserved
*y++ = dci->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
}
// Padding with zeros
uint32_t n = srsran_dci_format_sizeof(cell, sf, cfg, SRSRAN_DCI_FORMAT1A);
while (y - msg->payload < n) {
*y++ = 0;
}
msg->nof_bits = (y - msg->payload);
return SRSRAN_SUCCESS;
}
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
*/
static int dci_format1As_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
if (*y++ != 1) {
INFO("DCI message is Format0");
return SRSRAN_ERROR;
}
// Update DCI format
msg->format = SRSRAN_DCI_FORMAT1A;
// Check if RA procedure by PDCCH order
if (*y == 0) {
int nof_bits = riv_nbits(cell->nof_prb);
int i = 0;
// Check all bits in RBA are set to 1
while (i < nof_bits && y[1 + i] == 1) {
i++;
}
if (i == nof_bits) {
// Check all remaining bits are set to 0
i = 1 + 10 + nof_bits;
while (i < msg->nof_bits - 1 && y[i] == 0) {
i++;
}
if (i == msg->nof_bits - 1) {
// This is a Random access order
y += 1 + nof_bits;
dci->is_pdcch_order = true;
dci->preamble_idx = srsran_bit_pack(&y, 6);
dci->prach_mask_idx = srsran_bit_pack(&y, 4);
return SRSRAN_SUCCESS;
}
}
}
dci->is_pdcch_order = false;
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE2;
dci->type2_alloc.mode = *y++;
// by default, set N_gap to 1
dci->type2_alloc.n_gap = SRSRAN_RA_TYPE2_NG1;
/* unpack RIV */
uint32_t nb_gap = 0;
if (SRSRAN_RNTI_ISUSER(msg->rnti) && dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST && cell->nof_prb >= 50) {
nb_gap = 1;
dci->type2_alloc.n_gap = *y++;
}
uint32_t riv = srsran_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap);
dci->type2_alloc.riv = riv;
// unpack MCS
dci->tb[0].mcs_idx = srsran_bit_pack(&y, 5);
dci->pid = srsran_bit_pack(&y, HARQ_PID_LEN);
if (!SRSRAN_RNTI_ISUSER(msg->rnti)) {
if (cell->nof_prb >= 50 && dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST) {
dci->type2_alloc.n_gap = *y++;
} else {
y++; // NDI reserved
}
} else {
dci->tb[0].ndi = *y++ ? true : false;
}
// rv version
dci->tb[0].rv = srsran_bit_pack(&y, 2);
if (SRSRAN_RNTI_ISUSER(msg->rnti)) {
// TPC not implemented
y++;
y++;
} else {
y++; // MSB of TPC is reserved
dci->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
}
// TDD
if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
return SRSRAN_SUCCESS;
}
static int dci_format1B_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE2;
dci->type2_alloc.mode = *y++;
// by default, set N_gap to 1
dci->type2_alloc.n_gap = SRSRAN_RA_TYPE2_NG1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
uint32_t nb_gap = 0;
if (dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST && cell->nof_prb >= 50) {
nb_gap = 1;
dci->type2_alloc.n_gap = *y++;
}
uint32_t riv = srsran_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap);
dci->type2_alloc.riv = riv;
// unpack MCS, Harq pid and ndi
dci->tb[0].mcs_idx = srsran_bit_pack(&y, 5);
dci->pid = srsran_bit_pack(&y, HARQ_PID_LEN);
dci->tb[0].ndi = *y++ ? true : false;
dci->tb[0].rv = srsran_bit_pack(&y, 2);
// TPC PUCCH
dci->tpc_pucch = srsran_bit_pack(&y, 2);
// TDD
if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
dci->pinfo = srsran_bit_pack(&y, tpmi_bits(cell->nof_ports));
dci->pconf = *y++ ? true : false;
return SRSRAN_SUCCESS;
}
/* Format 1C for compact scheduling of PDSCH words
*
*/
static int dci_format1Cs_pack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_dl_t* dci,
srsran_dci_msg_t* msg)
{
uint32_t nof_prb = cell->nof_prb;
/* pack bits */
uint8_t* y = msg->payload;
if (dci->cif_present) {
srsran_bit_unpack(dci->cif, &y, 3);
}
if (dci->alloc_type != SRSRAN_RA_ALLOC_TYPE2 || dci->type2_alloc.mode != SRSRAN_RA_TYPE2_DIST) {
ERROR("Format 1C accepts distributed type2 resource allocation only");
return SRSRAN_ERROR;
}
if (nof_prb >= 50) {
*y++ = dci->type2_alloc.n_gap;
}
uint32_t n_step = srsran_ra_type2_n_rb_step(nof_prb);
uint32_t n_vrb_dl = srsran_ra_type2_n_vrb_dl(nof_prb, dci->type2_alloc.n_gap == SRSRAN_RA_TYPE2_NG1);
uint32_t riv = dci->type2_alloc.riv;
srsran_bit_unpack(riv, &y, riv_nbits((int)n_vrb_dl / n_step));
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
srsran_bit_unpack(dci->tb[0].mcs_idx, &y, 5);
msg->nof_bits = (y - msg->payload);
return SRSRAN_SUCCESS;
}
static int dci_format1Cs_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
if (msg->nof_bits != srsran_dci_format_sizeof(cell, sf, cfg, SRSRAN_DCI_FORMAT1C)) {
ERROR("Invalid message length for format 1C");
return SRSRAN_ERROR;
}
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE2;
dci->type2_alloc.mode = SRSRAN_RA_TYPE2_DIST;
if (cell->nof_prb >= 50) {
dci->type2_alloc.n_gap = *y++;
}
uint32_t n_step = srsran_ra_type2_n_rb_step(cell->nof_prb);
uint32_t n_vrb_dl = srsran_ra_type2_n_vrb_dl(cell->nof_prb, dci->type2_alloc.n_gap == SRSRAN_RA_TYPE2_NG1);
uint32_t riv = srsran_bit_pack(&y, riv_nbits((int)n_vrb_dl / n_step));
dci->type2_alloc.riv = riv;
dci->tb[0].mcs_idx = srsran_bit_pack(&y, 5);
dci->tb[0].rv = -1; // Get RV later
msg->nof_bits = (y - msg->payload);
return SRSRAN_SUCCESS;
}
static int dci_format1D_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE2;
dci->type2_alloc.mode = *y++;
// by default, set N_gap to 1
dci->type2_alloc.n_gap = SRSRAN_RA_TYPE2_NG1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
uint32_t nb_gap = 0;
if (dci->type2_alloc.mode == SRSRAN_RA_TYPE2_DIST && cell->nof_prb >= 50) {
nb_gap = 1;
dci->type2_alloc.n_gap = *y++;
}
uint32_t riv = srsran_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap);
dci->type2_alloc.riv = riv;
// unpack MCS, Harq pid and ndi
dci->tb[0].mcs_idx = srsran_bit_pack(&y, 5);
dci->pid = srsran_bit_pack(&y, HARQ_PID_LEN);
dci->tb[0].ndi = *y++ ? true : false;
dci->tb[0].rv = srsran_bit_pack(&y, 2);
// TPC PUCCH
dci->tpc_pucch = srsran_bit_pack(&y, 2);
// TDD
if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
dci->pinfo = srsran_bit_pack(&y, tpmi_bits(cell->nof_ports));
dci->power_offset = *y++ ? true : false;
return SRSRAN_SUCCESS;
}
static int dci_format2AB_pack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_dl_t* dci,
srsran_dci_msg_t* msg)
{
uint32_t nof_prb = cell->nof_prb;
uint32_t nof_ports = cell->nof_ports;
/* pack bits */
uint8_t* y = msg->payload;
if (dci->cif_present) {
srsran_bit_unpack(dci->cif, &y, 3);
}
if (nof_prb > 10) {
*y++ = dci->alloc_type;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = srsran_ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t)ceilf((float)nof_prb / P);
switch (dci->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
srsran_bit_unpack((uint32_t)dci->type0_alloc.rbg_bitmask, &y, alloc_size);
break;
case SRSRAN_RA_ALLOC_TYPE1:
srsran_bit_unpack((uint32_t)dci->type1_alloc.rbg_subset, &y, (int)ceilf(log2f(P)));
*y++ = dci->type1_alloc.shift ? 1 : 0;
srsran_bit_unpack((uint32_t)dci->type1_alloc.vrb_bitmask, &y, alloc_size - (int)ceilf(log2f(P)) - 1);
break;
default:
ERROR("Format 1 accepts type0 or type1 resource allocation only");
return SRSRAN_ERROR;
}
/* TCP command for PUCCH */
srsran_bit_unpack(dci->tpc_pucch, &y, 2);
/* harq process number */
srsran_bit_unpack(dci->pid, &y, HARQ_PID_LEN);
// Transpor block to codeword swap flag
if (msg->format == SRSRAN_DCI_FORMAT2B) {
*y++ = dci->sram_id;
} else {
*y++ = dci->tb_cw_swap;
}
/* pack TB1 */
srsran_bit_unpack(dci->tb[0].mcs_idx, &y, 5);
*y++ = dci->tb[0].ndi;
srsran_bit_unpack(dci->tb[0].rv, &y, 2);
/* pack TB2 */
srsran_bit_unpack(dci->tb[1].mcs_idx, &y, 5);
*y++ = dci->tb[1].ndi;
srsran_bit_unpack(dci->tb[1].rv, &y, 2);
// Precoding information
if (msg->format == SRSRAN_DCI_FORMAT2) {
srsran_bit_unpack(dci->pinfo, &y, precoding_bits_f2(nof_ports));
} else if (msg->format == SRSRAN_DCI_FORMAT2A) {
srsran_bit_unpack(dci->pinfo, &y, precoding_bits_f2a(nof_ports));
}
// Padding with zeros
uint32_t n = srsran_dci_format_sizeof(cell, sf, cfg, msg->format);
while (y - msg->payload < n) {
*y++ = 0;
}
msg->nof_bits = (y - msg->payload);
return SRSRAN_SUCCESS;
}
static int dci_format2AB_unpack(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
/* pack bits */
uint8_t* y = msg->payload;
if (cfg->cif_enabled) {
dci->cif = srsran_bit_pack(&y, 3);
dci->cif_present = true;
}
if (cell->nof_prb > 10) {
dci->alloc_type = *y++;
} else {
dci->alloc_type = SRSRAN_RA_ALLOC_TYPE0;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = srsran_ra_type0_P(cell->nof_prb);
uint32_t alloc_size = (uint32_t)ceilf((float)cell->nof_prb / P);
switch (dci->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
dci->type0_alloc.rbg_bitmask = srsran_bit_pack(&y, alloc_size);
break;
case SRSRAN_RA_ALLOC_TYPE1:
dci->type1_alloc.rbg_subset = srsran_bit_pack(&y, (int)ceilf(log2f(P)));
dci->type1_alloc.shift = *y++ ? true : false;
dci->type1_alloc.vrb_bitmask = srsran_bit_pack(&y, alloc_size - (int)ceilf(log2f(P)) - 1);
break;
default:
ERROR("Format2 accepts type0 or type1 resource allocation only");
return SRSRAN_ERROR;
}
// TPC PUCCH
dci->tpc_pucch = srsran_bit_pack(&y, 2);
// TDD
if (IS_TDD) {
dci->dai = srsran_bit_pack(&y, 2);
dci->is_tdd = true;
}
/* harq process number */
dci->pid = srsran_bit_pack(&y, HARQ_PID_LEN);
// Transpor block to codeword swap flag
if (msg->format == SRSRAN_DCI_FORMAT2B) {
dci->sram_id = *y++ ? true : false;
} else {
dci->tb_cw_swap = *y++ ? true : false;
}
uint32_t nof_tb = 0;
/* unpack MCS according to 7.1.7 of 36.213 */
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
dci->tb[i].mcs_idx = srsran_bit_pack(&y, 5);
dci->tb[i].ndi = *y++ ? true : false;
dci->tb[i].rv = srsran_bit_pack(&y, 2);
if (SRSRAN_DCI_IS_TB_EN(dci->tb[i])) {
nof_tb++;
}
}
// Precoding information
if (msg->format == SRSRAN_DCI_FORMAT2) {
dci->pinfo = srsran_bit_pack(&y, precoding_bits_f2(cell->nof_ports));
} else if (msg->format == SRSRAN_DCI_FORMAT2A) {
dci->pinfo = srsran_bit_pack(&y, precoding_bits_f2a(cell->nof_ports));
}
// Apply TB swap table according to 3GPP 36.212 R8, section 5.3.3.1.5
if (nof_tb == 2) {
// Table 5.3.3.1.5-1
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
dci->tb[i].cw_idx = (((dci->tb_cw_swap) ? 1 : 0) + i) % nof_tb;
}
} else {
// Table 5.3.3.1.5-2
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
dci->tb[i].cw_idx = 0;
}
}
return SRSRAN_SUCCESS;
}
int srsran_dci_msg_pack_pdsch(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_dl_t* dci,
srsran_dci_msg_t* msg)
{
int ret = SRSRAN_ERROR;
msg->rnti = dci->rnti;
msg->location = dci->location;
msg->format = dci->format;
srsran_dci_cfg_t _dci_cfg;
if (!cfg) {
ZERO_OBJECT(_dci_cfg);
cfg = &_dci_cfg;
}
switch (msg->format) {
case SRSRAN_DCI_FORMAT1:
ret = dci_format1_pack(cell, sf, cfg, dci, msg);
break;
case SRSRAN_DCI_FORMAT1A:
ret = dci_format1As_pack(cell, sf, cfg, dci, msg);
break;
case SRSRAN_DCI_FORMAT1C:
ret = dci_format1Cs_pack(cell, sf, cfg, dci, msg);
break;
case SRSRAN_DCI_FORMAT2:
case SRSRAN_DCI_FORMAT2A:
case SRSRAN_DCI_FORMAT2B:
ret = dci_format2AB_pack(cell, sf, cfg, dci, msg);
break;
default:
ERROR("DCI pack pdsch: Invalid DCI format %s", srsran_dci_format_string(msg->format));
}
#if SRSRAN_DCI_HEXDEBUG
srsran_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits);
dci->nof_bits = msg->nof_bits;
#endif /* SRSRAN_DCI_HEXDEBUG */
return ret;
}
int srsran_dci_msg_unpack_pdsch(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_dl_t* dci)
{
// Initialize DCI
bzero(dci, sizeof(srsran_dci_dl_t));
// Enable just 1 TB per default
for (int i = 1; i < SRSRAN_MAX_CODEWORDS; i++) {
SRSRAN_DCI_TB_DISABLE(dci->tb[i]);
}
dci->rnti = msg->rnti;
dci->location = msg->location;
dci->format = msg->format;
srsran_dci_cfg_t _dci_cfg;
if (!cfg) {
ZERO_OBJECT(_dci_cfg);
cfg = &_dci_cfg;
}
#if SRSRAN_DCI_HEXDEBUG
dci->hex_str[0] = '\0';
srsran_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits);
dci->nof_bits = msg->nof_bits;
#endif
// Set dwpts flag
dci->is_dwpts =
cell->frame_type == SRSRAN_TDD && srsran_sfidx_tdd_type(sf->tdd_config, sf->tti % 10) == SRSRAN_TDD_SF_S;
switch (msg->format) {
case SRSRAN_DCI_FORMAT1:
return dci_format1_unpack(cell, sf, cfg, msg, dci);
case SRSRAN_DCI_FORMAT1A:
return dci_format1As_unpack(cell, sf, cfg, msg, dci);
case SRSRAN_DCI_FORMAT1B:
return dci_format1B_unpack(cell, sf, cfg, msg, dci);
case SRSRAN_DCI_FORMAT1C:
return dci_format1Cs_unpack(cell, sf, cfg, msg, dci);
case SRSRAN_DCI_FORMAT1D:
return dci_format1D_unpack(cell, sf, cfg, msg, dci);
case SRSRAN_DCI_FORMAT2:
case SRSRAN_DCI_FORMAT2A:
case SRSRAN_DCI_FORMAT2B:
return dci_format2AB_unpack(cell, sf, cfg, msg, dci);
default:
ERROR("DCI unpack pdsch: Invalid DCI format %s", srsran_dci_format_string(msg->format));
return SRSRAN_ERROR;
}
}
int srsran_dci_msg_pack_pusch(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_ul_t* dci,
srsran_dci_msg_t* msg)
{
msg->rnti = dci->rnti;
msg->location = dci->location;
msg->format = dci->format;
srsran_dci_cfg_t _dci_cfg;
if (!cfg) {
ZERO_OBJECT(_dci_cfg);
cfg = &_dci_cfg;
}
int n = dci_format0_pack(cell, sf, cfg, dci, msg);
#if SRSRAN_DCI_HEXDEBUG
dci->hex_str[0] = '\0';
srsran_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits);
dci->nof_bits = msg->nof_bits;
#endif /* SRSRAN_DCI_HEXDEBUG */
return n;
}
int srsran_dci_msg_unpack_pusch(srsran_cell_t* cell,
srsran_dl_sf_cfg_t* sf,
srsran_dci_cfg_t* cfg,
srsran_dci_msg_t* msg,
srsran_dci_ul_t* dci)
{
// Initialize DCI
bzero(dci, sizeof(srsran_dci_ul_t));
dci->rnti = msg->rnti;
dci->location = msg->location;
dci->format = msg->format;
srsran_dci_cfg_t _dci_cfg;
if (!cfg) {
ZERO_OBJECT(_dci_cfg);
cfg = &_dci_cfg;
}
#if SRSRAN_DCI_HEXDEBUG
dci->hex_str[0] = '\0';
srsran_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits);
dci->nof_bits = msg->nof_bits;
#endif /* SRSRAN_DCI_HEXDEBUG */
return dci_format0_unpack(cell, sf, cfg, msg, dci);
}
bool srsran_location_find(const srsran_dci_location_t* locations, uint32_t nof_locations, srsran_dci_location_t x)
{
for (uint32_t i = 0; i < nof_locations; i++) {
if (locations[i].L == x.L && locations[i].ncce == x.ncce) {
return true;
}
}
return false;
}
bool srsran_location_find_location(const srsran_dci_location_t* locations,
uint32_t nof_locations,
const srsran_dci_location_t* location)
{
for (uint32_t i = 0; i < nof_locations; i++) {
if (locations[i].ncce == location->ncce && locations[i].L == location->L) {
return true;
}
}
return false;
}
// Set the configuration for Format0/1A messages allocated on Common SS
void srsran_dci_cfg_set_common_ss(srsran_dci_cfg_t* cfg)
{
cfg->is_not_ue_ss = true;
}
int srsran_dci_location_set(srsran_dci_location_t* c, uint32_t L, uint32_t nCCE)
{
if (L <= 3) {
c->L = L;
} else {
ERROR("Invalid L %d", L);
return SRSRAN_ERROR;
}
if (nCCE <= 87) {
c->ncce = nCCE;
} else {
ERROR("Invalid nCCE %d", nCCE);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
bool srsran_dci_location_isvalid(srsran_dci_location_t* c)
{
if (c->L <= 3 && c->ncce <= 87) {
return true;
} else {
return false;
}
}
srsran_dci_format_t srsran_dci_format_from_string(char* str)
{
if (!strcmp(str, "Format0")) {
return SRSRAN_DCI_FORMAT0;
} else if (!strcmp(str, "Format1")) {
return SRSRAN_DCI_FORMAT1;
} else if (!strcmp(str, "Format1A")) {
return SRSRAN_DCI_FORMAT1A;
} else if (!strcmp(str, "Format1B")) {
return SRSRAN_DCI_FORMAT1B;
} else if (!strcmp(str, "Format1C")) {
return SRSRAN_DCI_FORMAT1C;
} else if (!strcmp(str, "Format1D")) {
return SRSRAN_DCI_FORMAT1D;
} else if (!strcmp(str, "Format2")) {
return SRSRAN_DCI_FORMAT2;
} else if (!strcmp(str, "Format2A")) {
return SRSRAN_DCI_FORMAT2A;
} else if (!strcmp(str, "Format2B")) {
return SRSRAN_DCI_FORMAT2B;
} else if (!strcmp(str, "FormatN0")) {
return SRSRAN_DCI_FORMATN0;
} else if (!strcmp(str, "FormatN1")) {
return SRSRAN_DCI_FORMATN1;
} else if (!strcmp(str, "FormatN2")) {
return SRSRAN_DCI_FORMATN2;
} else {
return SRSRAN_DCI_NOF_FORMATS;
}
}
char* srsran_dci_format_string(srsran_dci_format_t format)
{
switch (format) {
case SRSRAN_DCI_FORMAT0:
return "Format0 ";
case SRSRAN_DCI_FORMAT1:
return "Format1 ";
case SRSRAN_DCI_FORMAT1A:
return "Format1A";
case SRSRAN_DCI_FORMAT1B:
return "Format1B";
case SRSRAN_DCI_FORMAT1C:
return "Format1C";
case SRSRAN_DCI_FORMAT1D:
return "Format1D";
case SRSRAN_DCI_FORMAT2:
return "Format2 ";
case SRSRAN_DCI_FORMAT2A:
return "Format2A";
case SRSRAN_DCI_FORMAT2B:
return "Format2B";
case SRSRAN_DCI_FORMATN0:
return "FormatN0";
case SRSRAN_DCI_FORMATN1:
return "FormatN1";
case SRSRAN_DCI_FORMATN2:
return "FormatN2";
default:
return "N/A"; // fatal error
}
}
char* srsran_dci_format_string_short(srsran_dci_format_t format)
{
switch (format) {
case SRSRAN_DCI_FORMAT0:
return "0";
case SRSRAN_DCI_FORMAT1:
return "1";
case SRSRAN_DCI_FORMAT1A:
return "1A";
case SRSRAN_DCI_FORMAT1B:
return "1B";
case SRSRAN_DCI_FORMAT1C:
return "1C";
case SRSRAN_DCI_FORMAT1D:
return "1D";
case SRSRAN_DCI_FORMAT2:
return "2";
case SRSRAN_DCI_FORMAT2A:
return "2A";
case SRSRAN_DCI_FORMAT2B:
return "2B";
default:
return "N/A"; // fatal error
}
}
static char* ra_type_string(srsran_ra_type_t alloc_type)
{
switch (alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
return "Type 0";
case SRSRAN_RA_ALLOC_TYPE1:
return "Type 1";
case SRSRAN_RA_ALLOC_TYPE2:
return "Type 2";
default:
return "N/A";
}
}
static char* freq_hop_fl_string(int freq_hop)
{
switch (freq_hop) {
case 0:
return "1/4";
case 1:
return "-1/4";
case 2:
return "1/2";
case 3:
return "type2";
}
return "n/a";
}
void srsran_dci_dl_fprint(FILE* f, srsran_dci_dl_t* dci, uint32_t nof_prb)
{
if (dci->is_pdcch_order) {
fprintf(f, "PDCCH order:\n");
if (dci->cif_present) {
fprintf(f, " - Carrier idx:\t\t\t\t%d\n", dci->cif);
}
fprintf(f, " - Preamble index:\t\t%d\n", dci->preamble_idx);
fprintf(f, " - PRACH mask index:\t\t%d\n", dci->prach_mask_idx);
} else {
fprintf(f, " - Resource Allocation Type:\t\t%s\n", ra_type_string(dci->alloc_type));
switch (dci->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
fprintf(f, " + Resource Block Group Size:\t\t%d\n", srsran_ra_type0_P(nof_prb));
fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type0_alloc.rbg_bitmask);
break;
case SRSRAN_RA_ALLOC_TYPE1:
fprintf(f, " + Resource Block Group Size:\t\t%d\n", srsran_ra_type0_P(nof_prb));
fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type1_alloc.vrb_bitmask);
fprintf(f, " + RBG Subset:\t\t\t%d\n", dci->type1_alloc.rbg_subset);
fprintf(f, " + RBG Shift:\t\t\t\t%s\n", dci->type1_alloc.shift ? "Yes" : "No");
break;
case SRSRAN_RA_ALLOC_TYPE2:
fprintf(
f, " + Type:\t\t\t\t%s\n", dci->type2_alloc.mode == SRSRAN_RA_TYPE2_LOC ? "Localized" : "Distributed");
fprintf(f, " + Resource Indicator Value:\t\t%d\n", dci->type2_alloc.riv);
break;
}
if (dci->cif_present) {
fprintf(f, " - Carrier idx:\t\t\t\t%d\n", dci->cif);
}
fprintf(f, " - HARQ process:\t\t\t%d\n", dci->pid);
fprintf(f, " - TPC command for PUCCH:\t\t--\n");
fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap) ? "true" : "false");
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
fprintf(f, " - Transport block %d enabled:\t\t%s\n", i, SRSRAN_DCI_IS_TB_EN(dci->tb[i]) ? "true" : "false");
if (SRSRAN_DCI_IS_TB_EN(dci->tb[i])) {
fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->tb[i].mcs_idx);
fprintf(f, " + New data indicator:\t\t\t%s\n", dci->tb[i].ndi ? "Yes" : "No");
fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->tb[i].rv);
}
}
}
}
static uint32_t print_multi(char* info_str, uint32_t n, uint32_t len, const srsran_dci_dl_t* dci_dl, uint32_t value_id)
{
uint32_t nof_tb = 1;
if (dci_dl->format >= SRSRAN_DCI_FORMAT2) {
nof_tb = 2;
}
for (uint32_t i = 0; i < nof_tb; i++) {
switch (value_id) {
case 0:
n = srsran_print_check(info_str, len, n, "%d", dci_dl->tb[i].mcs_idx);
break;
case 1:
n = srsran_print_check(info_str, len, n, "%d", dci_dl->tb[i].rv);
break;
case 2:
n = srsran_print_check(info_str, len, n, "%d", dci_dl->tb[i].ndi);
break;
}
if (i < SRSRAN_MAX_CODEWORDS - 1 && nof_tb > 1) {
n = srsran_print_check(info_str, len, n, "/");
}
}
return n;
}
uint32_t srsran_dci_dl_info(const srsran_dci_dl_t* dci_dl, char* info_str, uint32_t len)
{
uint32_t n = 0;
n = srsran_print_check(info_str,
len,
0,
"f=%s, cce=%2d, L=%d",
srsran_dci_format_string_short(dci_dl->format),
dci_dl->location.ncce,
dci_dl->location.L);
if (dci_dl->cif_present) {
n = srsran_print_check(info_str, len, n, ", cif=%d", dci_dl->cif);
}
if (dci_dl->is_pdcch_order) {
n = srsran_print_check(info_str, len, n, ", preamb_idx=%d", dci_dl->preamble_idx);
n = srsran_print_check(info_str, len, n, ", prach_mask_idx=%d", dci_dl->prach_mask_idx);
} else {
switch (dci_dl->alloc_type) {
case SRSRAN_RA_ALLOC_TYPE0:
n = srsran_print_check(info_str, len, n, ", rbg=0x%x", dci_dl->type0_alloc.rbg_bitmask);
break;
case SRSRAN_RA_ALLOC_TYPE1:
n = srsran_print_check(info_str,
len,
n,
", vrb=0x%x, rbg_s=%d, sh=%d",
dci_dl->type1_alloc.vrb_bitmask,
dci_dl->type1_alloc.rbg_subset,
dci_dl->type1_alloc.shift);
break;
case SRSRAN_RA_ALLOC_TYPE2:
n = srsran_print_check(info_str, len, n, ", riv=%d", dci_dl->type2_alloc.riv);
break;
}
n = srsran_print_check(info_str, len, n, ", pid=%d", dci_dl->pid);
n = srsran_print_check(info_str, len, n, ", mcs={");
n = print_multi(info_str, n, len, dci_dl, 0);
n = srsran_print_check(info_str, len, n, "}");
n = srsran_print_check(info_str, len, n, ", ndi={");
n = print_multi(info_str, n, len, dci_dl, 2);
n = srsran_print_check(info_str, len, n, "}");
if (dci_dl->format == SRSRAN_DCI_FORMAT1 || dci_dl->format == SRSRAN_DCI_FORMAT1A ||
dci_dl->format == SRSRAN_DCI_FORMAT1B || dci_dl->format == SRSRAN_DCI_FORMAT2 ||
dci_dl->format == SRSRAN_DCI_FORMAT2A || dci_dl->format == SRSRAN_DCI_FORMAT2B) {
n = srsran_print_check(info_str, len, n, ", tpc_pucch=%d", dci_dl->tpc_pucch);
}
if (dci_dl->is_tdd) {
n = srsran_print_check(info_str, len, n, ", dai=%d", dci_dl->dai);
}
if (dci_dl->format == SRSRAN_DCI_FORMAT2 || dci_dl->format == SRSRAN_DCI_FORMAT2A ||
dci_dl->format == SRSRAN_DCI_FORMAT2B) {
n = srsran_print_check(info_str, len, n, ", tb_sw=%d, pinfo=%d", dci_dl->tb_cw_swap, dci_dl->pinfo);
}
}
#if SRSRAN_DCI_HEXDEBUG
n = srsran_print_check(info_str, len, n, ", len=%d, hex=%s", dci_dl->nof_bits, dci_dl->hex_str);
#endif /* SRSRAN_DCI_HEXDEBUG */
return n;
}
uint32_t srsran_dci_ul_info(srsran_dci_ul_t* dci_ul, char* info_str, uint32_t len)
{
uint32_t n = 0;
n = srsran_print_check(info_str, len, n, "f=0, ");
if (dci_ul->cif_present) {
n = srsran_print_check(info_str, len, n, "cif=%d, ", dci_ul->cif);
}
n = srsran_print_check(info_str,
len,
n,
"cce=%2d, L=%d, riv=%d, mcs=%d, rv=%d, ndi=%d, f_h=%s, cqi=%s, tpc_pusch=%d, dmrs_cs=%d",
dci_ul->location.ncce,
dci_ul->location.L,
dci_ul->type2_alloc.riv,
dci_ul->tb.mcs_idx,
dci_ul->tb.rv,
dci_ul->tb.ndi,
freq_hop_fl_string(dci_ul->freq_hop_fl),
dci_ul->cqi_request ? "yes" : "no",
dci_ul->tpc_pusch,
dci_ul->n_dmrs);
if (dci_ul->multiple_csi_request_present) {
n = srsran_print_check(info_str, len, n, ", csi=%d", dci_ul->multiple_csi_request);
}
if (dci_ul->srs_request_present) {
n = srsran_print_check(info_str, len, n, ", srs_request=%s", dci_ul->srs_request ? "yes" : "no");
}
if (dci_ul->ra_type_present) {
n = srsran_print_check(info_str, len, n, ", ra_type=%s", dci_ul->ra_type ? "yes" : "no");
}
if (dci_ul->is_tdd) {
n = srsran_print_check(info_str, len, n, ", ul_idx=%d, dai=%d", dci_ul->ul_idx, dci_ul->dai);
}
#if SRSRAN_DCI_HEXDEBUG
n = srsran_print_check(info_str, len, n, ", len=%d, hex=%s", dci_ul->nof_bits, dci_ul->hex_str);
#endif /* SRSRAN_DCI_HEXDEBUG */
return n;
}
uint32_t srsran_dci_format_max_tb(srsran_dci_format_t format)
{
uint32_t ret = 0;
switch (format) {
case SRSRAN_DCI_FORMAT0:
case SRSRAN_DCI_FORMAT1:
case SRSRAN_DCI_FORMAT1A:
case SRSRAN_DCI_FORMAT1C:
case SRSRAN_DCI_FORMAT1B:
case SRSRAN_DCI_FORMAT1D:
case SRSRAN_DCI_FORMATN0:
case SRSRAN_DCI_FORMATN1:
case SRSRAN_DCI_FORMATN2:
case SRSRAN_DCI_FORMAT_RAR:
ret = 1;
break;
case SRSRAN_DCI_FORMAT2:
case SRSRAN_DCI_FORMAT2A:
case SRSRAN_DCI_FORMAT2B:
ret = 2;
break;
case SRSRAN_DCI_NOF_FORMATS:
default:
ret = 0;
break;
}
return ret;
}