mirror of https://github.com/PentHertz/srsLTE.git
1783 lines
52 KiB
C
1783 lines
52 KiB
C
/**
|
||
* 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;
|
||
}
|