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

807 lines
22 KiB
C
Raw Normal View History

2014-04-17 03:28:21 -07:00
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "liblte/phy/phch/dci.h"
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/utils/bit.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
2014-04-17 03:28:21 -07:00
int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti,
lte_cell_t cell, uint32_t cfi,
ra_pdsch_t *ra_dl)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (msg != NULL &&
ra_dl != NULL &&
lte_cell_isvalid(&cell) &&
cfi > 0 &&
cfi < 4)
{
ret = LIBLTE_ERROR;
dci_msg_type_t type;
if (dci_msg_get_type(msg, &type, cell.nof_prb, msg_rnti, c_rnti)) {
fprintf(stderr, "Can't get DCI message type\n");
return ret;
}
if (VERBOSE_ISINFO()) {
dci_msg_type_fprint(stdout, type);
}
if (type.type == PDSCH_SCHED) {
bzero(ra_dl, sizeof(ra_pdsch_t));
if (dci_msg_unpack_pdsch(msg, ra_dl, cell.nof_prb, msg_rnti != SIRNTI)) {
fprintf(stderr, "Can't unpack PDSCH message\n");
return ret;
}
if (VERBOSE_ISINFO()) {
ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb);
}
if (ra_prb_get_dl(&ra_dl->prb_alloc, ra_dl, cell.nof_prb)) {
fprintf(stderr, "Error computing resource allocation\n");
return ret;
}
ra_prb_get_re_dl(&ra_dl->prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp);
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
if (L <= 3) {
c->L = L;
2014-06-17 02:11:41 -07:00
} else {
fprintf(stderr, "Invalid L %d\n", L);
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (nCCE <= 87) {
c->ncce = nCCE;
2014-06-17 02:11:41 -07:00
} else {
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
return LIBLTE_SUCCESS;
2014-04-17 03:28:21 -07:00
}
bool dci_location_isvalid(dci_location_t *c) {
if (c->L <= 3 && c->ncce <= 87) {
return true;
} else {
return false;
}
}
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 };
bool is_ambiguous_size(uint32_t size) {
2014-06-17 02:11:41 -07:00
int i;
2014-06-17 07:32:19 -07:00
for (i = 0; i < 10; i++) {
2014-06-17 02:11:41 -07:00
if (size == ambiguous_sizes[i]) {
return true;
}
}
return false;
}
/**********************************
* PAYLOAD sizeof functions
* ********************************/
uint32_t dci_format0_sizeof_(uint32_t nof_prb) {
2014-06-17 07:32:19 -07:00
return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1;
}
uint32_t dci_format1A_sizeof(uint32_t nof_prb) {
uint32_t n;
2014-06-17 07:32:19 -07:00
n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2;
while (n < dci_format0_sizeof_(nof_prb)) {
2014-06-17 02:11:41 -07:00
n++;
}
if (is_ambiguous_size(n)) {
n++;
}
return n;
}
uint32_t dci_format0_sizeof(uint32_t nof_prb) {
uint32_t n = dci_format0_sizeof_(nof_prb);
2014-06-17 02:11:41 -07:00
while (n < dci_format1A_sizeof(nof_prb)) {
n++;
}
return n;
}
uint32_t dci_format1_sizeof(uint32_t nof_prb) {
uint32_t n = (uint32_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2
2014-06-17 07:32:19 -07:00
+ 2;
2014-06-17 02:11:41 -07:00
if (nof_prb > 10) {
n++;
}
2014-06-17 07:32:19 -07:00
while (n == dci_format0_sizeof(nof_prb) || n == dci_format1A_sizeof(nof_prb)
2014-06-17 02:11:41 -07:00
|| is_ambiguous_size(n)) {
n++;
}
return n;
}
uint32_t dci_format1C_sizeof(uint32_t nof_prb) {
uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5;
2014-06-17 02:11:41 -07:00
if (nof_prb >= 50) {
n++;
}
return n;
}
uint32_t dci_format_sizeof(dci_format_t format, uint32_t nof_prb) {
2014-06-17 07:32:19 -07:00
switch (format) {
2014-06-17 02:11:41 -07:00
case Format0:
return dci_format0_sizeof(nof_prb);
case Format1:
return dci_format1_sizeof(nof_prb);
case Format1A:
return dci_format1A_sizeof(nof_prb);
case Format1C:
return dci_format1C_sizeof(nof_prb);
default:
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
}
/**********************************
* 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
*/
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
uint32_t n_ul_hop;
2014-06-17 02:11:41 -07:00
*y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
*y++ = 0;
n_ul_hop = 0;
} else {
*y++ = 1;
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
*y++ = data->freq_hop_fl & 1;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
*y++ = (data->freq_hop_fl & 2) >> 1;
*y++ = data->freq_hop_fl & 1;
}
}
/* pack RIV according to 8.1 of 36.213 */
uint32_t riv;
2014-06-17 02:11:41 -07:00
if (data->type2_alloc.L_crb) {
2014-06-17 07:32:19 -07:00
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
nof_prb);
2014-06-17 02:11:41 -07:00
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
2014-06-17 02:11:41 -07:00
/* pack MCS according to 8.6.1 of 36.213 */
bit_pack(data->mcs_idx, &y, 5);
2014-06-17 02:11:41 -07:00
*y++ = data->ndi;
// TCP commands not implemented
*y++ = 0;
*y++ = 0;
// DM RS not implemented
*y++ = 0;
*y++ = 0;
*y++ = 0;
// CQI request
*y++ = data->cqi_request;
// Padding with zeros
uint32_t n = dci_format0_sizeof(nof_prb);
2014-06-17 07:32:19 -07:00
while (y - msg->data < n) {
2014-06-17 02:11:41 -07:00
*y++ = 0;
}
msg->nof_bits = (y - msg->data);
return LIBLTE_SUCCESS;
2014-04-17 03:28:21 -07:00
}
/* 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
*/
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
2014-04-17 03:28:21 -07:00
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
uint32_t n_ul_hop;
2014-06-17 02:11:41 -07:00
/* Make sure it's a Format0 message */
if (msg->nof_bits != dci_format_sizeof(Format0, nof_prb)) {
2014-06-17 02:11:41 -07:00
fprintf(stderr, "Invalid message length for format 0\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (*y++ != 0) {
2014-06-17 07:32:19 -07:00
fprintf(stderr,
"Invalid format differentiation field value. This is Format1A\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (*y++ == 0) {
data->freq_hop_fl = hop_disabled;
n_ul_hop = 0;
} else {
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
data->freq_hop_fl = *y++;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
2014-06-17 07:32:19 -07:00
data->freq_hop_fl = y[0] << 1 | y[1];
2014-06-17 02:11:41 -07:00
y += 2;
}
}
/* unpack RIV according to 8.1 of 36.213 */
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
2014-06-17 07:32:19 -07:00
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_prb);
bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop);
2014-06-17 02:11:41 -07:00
data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */
data->mcs_idx = bit_unpack(&y, 5);
2014-06-17 02:11:41 -07:00
2014-06-17 07:32:19 -07:00
data->ndi = *y++ ? true : false;
2014-06-17 02:11:41 -07:00
// TCP and DM RS commands not implemented
2014-06-17 07:32:19 -07:00
y += 5;
2014-06-17 02:11:41 -07:00
// CQI request
2014-06-17 07:32:19 -07:00
data->cqi_request = *y++ ? true : false;
2014-06-17 02:11:41 -07:00
// 8.6.2 First paragraph
if (data->mcs_idx <= 28) {
ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs);
} else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
// 8.6.1 and 8.6.2 36.213 second paragraph
data->mcs.mod = LTE_QPSK;
data->mcs.tbs = 0;
} else if (data->mcs_idx >= 29) {
// Else leave TBS and use the previously used PUSCH modulation
data->mcs.tbs = 0;
data->rv_idx = data->mcs_idx - 28;
2014-06-17 02:11:41 -07:00
}
return LIBLTE_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
*/
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
if (nof_prb > 10) {
*y++ = data->alloc_type;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
2014-06-17 07:32:19 -07:00
switch (data->alloc_type) {
2014-06-17 02:11:41 -07:00
case alloc_type0:
bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size);
2014-06-17 02:11:41 -07:00
break;
case alloc_type1:
bit_pack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
2014-06-17 07:32:19 -07:00
*y++ = data->type1_alloc.shift ? 1 : 0;
bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y,
2014-06-17 07:32:19 -07:00
alloc_size - (int) ceilf(log2f(P)) - 1);
2014-06-17 02:11:41 -07:00
break;
default:
2014-06-17 07:32:19 -07:00
fprintf(stderr,
"Format 1 accepts type0 or type1 resource allocation only\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
/* pack MCS */
bit_pack(data->mcs_idx, &y, 5);
2014-06-17 02:11:41 -07:00
/* harq process number */
bit_pack(data->harq_process, &y, 3);
2014-06-17 02:11:41 -07:00
*y++ = data->ndi;
// rv version
bit_pack(data->rv_idx, &y, 2);
2014-06-17 02:11:41 -07:00
// TPC not implemented
*y++ = 0;
*y++ = 0;
// Padding with zeros
uint32_t n = dci_format1_sizeof(nof_prb);
2014-06-17 07:32:19 -07:00
while (y - msg->data < n) {
2014-06-17 02:11:41 -07:00
*y++ = 0;
}
msg->nof_bits = (y - msg->data);
2014-06-17 02:11:41 -07:00
return LIBLTE_SUCCESS;
}
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format1 message */
if (msg->nof_bits != dci_format_sizeof(Format1, nof_prb)) {
2014-06-17 02:11:41 -07:00
fprintf(stderr, "Invalid message length for format 1\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (nof_prb > 10) {
data->alloc_type = *y++;
} else {
data->alloc_type = alloc_type0;
}
/* Resource allocation: type0 or type 1 */
uint32_t P = ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
2014-06-17 07:32:19 -07:00
switch (data->alloc_type) {
2014-06-17 02:11:41 -07:00
case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
break;
case alloc_type1:
data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P)));
2014-06-17 07:32:19 -07:00
data->type1_alloc.shift = *y++ ? true : false;
data->type1_alloc.vrb_bitmask = bit_unpack(&y,
alloc_size - (int) ceilf(log2f(P)) - 1);
2014-06-17 02:11:41 -07:00
break;
default:
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
/* unpack MCS according to 7.1.7 of 36.213 */
data->mcs_idx = bit_unpack(&y, 5);
if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) {
fprintf(stderr, "Error getting MCS\n");
return LIBLTE_ERROR;
}
2014-06-17 02:11:41 -07:00
/* harq process number */
data->harq_process = bit_unpack(&y, 3);
2014-06-17 07:32:19 -07:00
data->ndi = *y++ ? true : false;
2014-06-17 02:11:41 -07:00
// rv version
data->rv_idx = bit_unpack(&y, 2);
// TPC not implemented
return LIBLTE_SUCCESS;
2014-04-17 03:28:21 -07:00
}
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
* TODO: RA procedure initiated by PDCCH, TPC commands
*/
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb,
2014-06-17 07:32:19 -07:00
bool crc_is_crnti) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
*y++ = 1; // format differentiation
if (data->alloc_type != alloc_type2) {
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
if (data->type2_alloc.mode == t2_loc) {
if (data->type2_alloc.L_crb > nof_prb) {
2014-06-17 07:32:19 -07:00
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n",
data->type2_alloc.L_crb);
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
} else {
uint32_t n_vrb_dl;
2014-06-17 02:11:41 -07:00
if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16;
} else {
2014-06-17 07:32:19 -07:00
n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
2014-06-17 02:11:41 -07:00
}
if (data->type2_alloc.L_crb > n_vrb_dl) {
2014-06-17 07:32:19 -07:00
fprintf(stderr,
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, n_vrb_dl);
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
}
/* pack RIV according to 7.1.6.3 of 36.213 */
uint32_t riv;
2014-06-17 02:11:41 -07:00
if (data->type2_alloc.L_crb) {
2014-06-17 07:32:19 -07:00
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
nof_prb);
2014-06-17 02:11:41 -07:00
} else {
riv = data->type2_alloc.riv;
}
uint32_t nb_gap = 0;
2014-06-17 02:11:41 -07:00
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
*y++ = data->type2_alloc.n_gap;
}
bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap);
2014-06-17 02:11:41 -07:00
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
bit_pack(data->mcs_idx, &y, 5);
2014-06-17 02:11:41 -07:00
bit_pack(data->harq_process, &y, 3);
2014-06-17 02:11:41 -07:00
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
*y++ = data->type2_alloc.n_gap;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
2014-06-17 02:11:41 -07:00
if (crc_is_crnti) {
// TPC not implemented
*y++ = 0;
*y++ = 0;
} else {
y++; // MSB of TPC is reserved
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
// Padding with zeros
uint32_t n = dci_format1A_sizeof(nof_prb);
2014-06-17 07:32:19 -07:00
while (y - msg->data < n) {
2014-06-17 02:11:41 -07:00
*y++ = 0;
}
msg->nof_bits = (y - msg->data);
2014-06-17 02:11:41 -07:00
return LIBLTE_SUCCESS;
2014-04-17 03:28:21 -07:00
}
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
*/
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
2014-06-17 07:32:19 -07:00
bool crc_is_crnti) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format0 message */
if (msg->nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
2014-06-17 02:11:41 -07:00
fprintf(stderr, "Invalid message length for format 1A\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
2014-06-17 07:32:19 -07:00
2014-06-17 02:11:41 -07:00
if (*y++ != 1) {
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = *y++;
// by default, set N_gap to 1
data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
uint32_t nb_gap = 0;
2014-06-17 02:11:41 -07:00
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
data->type2_alloc.n_gap = *y++;
}
uint32_t nof_vrb;
2014-06-17 02:11:41 -07:00
if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb;
} else {
nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
}
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap);
2014-06-17 07:32:19 -07:00
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_vrb);
2014-06-17 02:11:41 -07:00
data->type2_alloc.riv = riv;
// unpack MCS
data->mcs_idx = bit_unpack(&y, 5);
2014-06-17 02:11:41 -07:00
data->harq_process = bit_unpack(&y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
data->type2_alloc.n_gap = *y++;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
2014-06-17 02:11:41 -07:00
if (crc_is_crnti) {
// TPC not implemented
y++;
y++;
} else {
y++; // MSB of TPC is reserved
2014-06-17 07:32:19 -07:00
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
2014-06-17 02:11:41 -07:00
}
uint32_t n_prb;
2014-06-17 02:11:41 -07:00
if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
2014-06-17 07:32:19 -07:00
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3;
2014-06-17 02:11:41 -07:00
}
data->mcs.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb);
data->mcs.mod = LTE_QPSK;
2014-06-17 02:11:41 -07:00
return LIBLTE_SUCCESS;
2014-04-17 03:28:21 -07:00
}
/* Format 1C for compact scheduling of PDSCH words
*
*/
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
2014-06-17 07:32:19 -07:00
fprintf(stderr,
"Format 1C accepts distributed type2 resource allocation only\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap;
}
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
2014-06-17 02:11:41 -07:00
if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step);
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (data->type2_alloc.L_crb % n_step) {
fprintf(stderr, "L_crb must be multiple of n_step\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
if (data->type2_alloc.RB_start % n_step) {
fprintf(stderr, "RB_start must be multiple of n_step\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
uint32_t L_p = data->type2_alloc.L_crb / n_step;
uint32_t RB_p = data->type2_alloc.RB_start / n_step;
uint32_t n_vrb_p = (int) n_vrb_dl / n_step;
2014-06-17 02:11:41 -07:00
uint32_t riv;
2014-06-17 02:11:41 -07:00
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step));
2014-06-17 02:11:41 -07:00
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
bit_pack(data->mcs_idx, &y, 5);
2014-06-17 02:11:41 -07:00
msg->nof_bits = (y - msg->data);
2014-06-17 02:11:41 -07:00
return LIBLTE_SUCCESS;
}
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
uint32_t L_p, RB_p;
2014-06-17 02:11:41 -07:00
/* pack bits */
char *y = msg->data;
if (msg->nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
2014-06-17 02:11:41 -07:00
fprintf(stderr, "Invalid message length for format 1C\n");
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = t2_dist;
if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++;
}
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
2014-06-17 02:11:41 -07:00
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step));
uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step;
2014-06-17 02:11:41 -07:00
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
data->type2_alloc.L_crb = L_p * n_step;
data->type2_alloc.RB_start = RB_p * n_step;
data->type2_alloc.riv = riv;
data->mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx);
data->mcs.mod = LTE_QPSK;
2014-06-17 02:11:41 -07:00
msg->nof_bits = (y - msg->data);
2014-06-17 02:11:41 -07:00
return LIBLTE_SUCCESS;
}
2014-06-17 07:32:19 -07:00
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format,
uint32_t nof_prb, bool crc_is_crnti) {
2014-06-17 07:32:19 -07:00
switch (format) {
2014-06-17 02:11:41 -07:00
case Format1:
return dci_format1_pack(data, msg, nof_prb);
case Format1A:
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
case Format1C:
return dci_format1Cs_pack(data, msg, nof_prb);
default:
2014-06-17 07:32:19 -07:00
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n",
dci_format_string(format));
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
}
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
2014-06-17 07:32:19 -07:00
bool crc_is_crnti) {
if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
2014-06-17 02:11:41 -07:00
return dci_format1_unpack(msg, data, nof_prb);
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
2014-06-17 02:11:41 -07:00
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
2014-06-17 02:11:41 -07:00
return dci_format1Cs_unpack(msg, data, nof_prb);
} else {
return LIBLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
2014-04-17 03:28:21 -07:00
}
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
return dci_format0_pack(data, msg, nof_prb);
}
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
2014-06-17 02:11:41 -07:00
return dci_format0_unpack(msg, data, nof_prb);
}
char* dci_format_string(dci_format_t format) {
2014-06-17 07:32:19 -07:00
switch (format) {
2014-06-17 02:11:41 -07:00
case Format0:
return "Format0";
case Format1:
return "Format1";
case Format1A:
return "Format1A";
case Format1C:
return "Format1C";
default:
return "N/A"; // fatal error
}
}
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
2014-06-17 07:32:19 -07:00
switch (type.type) {
2014-06-17 02:11:41 -07:00
case PUSCH_SCHED:
2014-06-17 07:32:19 -07:00
fprintf(f, "%s PUSCH Scheduling\n", dci_format_string(type.format));
2014-06-17 02:11:41 -07:00
break;
case PDSCH_SCHED:
2014-06-17 07:32:19 -07:00
fprintf(f, "%s PDSCH Scheduling\n", dci_format_string(type.format));
2014-06-17 02:11:41 -07:00
break;
case RA_PROC_PDCCH:
2014-06-17 07:32:19 -07:00
fprintf(f, "%s Random access initiated by PDCCH\n",
dci_format_string(type.format));
2014-06-17 02:11:41 -07:00
break;
case MCCH_CHANGE:
2014-06-17 07:32:19 -07:00
fprintf(f, "%s MCCH change notification\n", dci_format_string(type.format));
2014-06-17 02:11:41 -07:00
break;
case TPC_COMMAND:
2014-06-17 07:32:19 -07:00
fprintf(f, "%s TPC command\n", dci_format_string(type.format));
2014-06-17 02:11:41 -07:00
break;
}
}
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb,
uint16_t msg_rnti, uint16_t crnti)
{
DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x, crnti=0x%x\n", msg->nof_bits, msg_rnti, crnti);
if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb)
2014-06-17 02:11:41 -07:00
&& !msg->data[0]) {
type->type = PUSCH_SCHED;
type->format = Format0;
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
2014-06-17 02:11:41 -07:00
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1;
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg_rnti == crnti) {
2014-06-17 02:11:41 -07:00
type->type = RA_PROC_PDCCH;
type->format = Format1A;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1A;
}
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg_rnti == MRNTI) {
2014-06-17 02:11:41 -07:00
type->type = MCCH_CHANGE;
type->format = Format1C;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1C;
}
return LIBLTE_SUCCESS;
2014-06-17 02:11:41 -07:00
}
return LIBLTE_ERROR;
}