|
|
|
/**
|
|
|
|
*
|
|
|
|
* \section COPYRIGHT
|
|
|
|
*
|
|
|
|
* Copyright 2013-2015 Software Radio Systems Limited
|
|
|
|
*
|
|
|
|
* \section LICENSE
|
|
|
|
*
|
|
|
|
* This file is part of the srsLTE library.
|
|
|
|
*
|
|
|
|
* srsLTE 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.
|
|
|
|
*
|
|
|
|
* srsLTE 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 <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <strings.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "srslte/phch/dci.h"
|
|
|
|
#include "srslte/common/phy_common.h"
|
|
|
|
#include "srslte/utils/bit.h"
|
|
|
|
#include "srslte/utils/vector.h"
|
|
|
|
#include "srslte/utils/debug.h"
|
|
|
|
|
|
|
|
#include "dci_sz_table.h"
|
|
|
|
|
|
|
|
int harq_pid_len = 3;
|
|
|
|
|
|
|
|
/* Unpacks a DCI message and configures the DL grant object
|
|
|
|
*/
|
|
|
|
int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, uint16_t msg_rnti,
|
|
|
|
uint32_t nof_prb, uint32_t nof_ports,
|
|
|
|
srslte_ra_dl_dci_t *dl_dci,
|
|
|
|
srslte_ra_dl_grant_t *grant)
|
|
|
|
{
|
|
|
|
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
|
|
|
|
if (msg != NULL &&
|
|
|
|
grant != NULL)
|
|
|
|
{
|
|
|
|
ret = SRSLTE_ERROR;
|
|
|
|
|
|
|
|
bzero(dl_dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
bzero(grant, sizeof(srslte_ra_dl_grant_t));
|
|
|
|
|
|
|
|
bool crc_is_crnti = false;
|
|
|
|
if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) {
|
|
|
|
crc_is_crnti = true;
|
|
|
|
}
|
|
|
|
//srslte_dci_format_t tmp = msg->format;
|
|
|
|
ret = srslte_dci_msg_unpack_pdsch(msg, dl_dci, nof_prb, nof_ports, crc_is_crnti);
|
|
|
|
if (ret) {
|
|
|
|
//fprintf(stderr, "Can't unpack DCI message %s (%d)\n", srslte_dci_format_string(msg->format), msg->format);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srslte_ra_dl_dci_to_grant(dl_dci, nof_prb, msg_rnti, grant);
|
|
|
|
|
|
|
|
if (SRSLTE_VERBOSE_ISINFO()) {
|
|
|
|
srslte_ra_pdsch_fprint(stdout, dl_dci, nof_prb);
|
|
|
|
srslte_ra_dl_grant_fprint(stdout, grant);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Creates the UL PUSCH resource allocation grant from the random access respone message
|
|
|
|
*/
|
|
|
|
int srslte_dci_rar_to_ul_grant(srslte_dci_rar_grant_t *rar, uint32_t nof_prb,
|
|
|
|
uint32_t n_rb_ho,
|
|
|
|
srslte_ra_ul_dci_t *ul_dci,
|
|
|
|
srslte_ra_ul_grant_t *grant)
|
|
|
|
{
|
|
|
|
bzero(ul_dci, sizeof(srslte_ra_ul_dci_t));
|
|
|
|
|
|
|
|
if (!rar->hopping_flag) {
|
|
|
|
ul_dci->freq_hop_fl = SRSLTE_RA_PUSCH_HOP_DISABLED;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "FIXME: Frequency hopping in RAR not implemented\n");
|
|
|
|
ul_dci->freq_hop_fl = 1;
|
|
|
|
}
|
|
|
|
uint32_t riv = rar->rba;
|
|
|
|
// Truncate resource block assignment
|
|
|
|
uint32_t b = 0;
|
|
|
|
if (nof_prb <= 44) {
|
|
|
|
b = (uint32_t) (ceilf(log2((float) nof_prb*(nof_prb+1)/2)));
|
|
|
|
riv = riv & ((1<<(b+1))-1);
|
|
|
|
}
|
|
|
|
ul_dci->type2_alloc.riv = riv;
|
|
|
|
ul_dci->mcs_idx = rar->trunc_mcs;
|
|
|
|
|
|
|
|
srslte_ra_type2_from_riv(riv, &ul_dci->type2_alloc.L_crb, &ul_dci->type2_alloc.RB_start,
|
|
|
|
nof_prb, nof_prb);
|
|
|
|
|
|
|
|
if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, 0)) {
|
|
|
|
fprintf(stderr, "Error computing resource allocation\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SRSLTE_VERBOSE_ISINFO()) {
|
|
|
|
srslte_ra_pusch_fprint(stdout, ul_dci, nof_prb);
|
|
|
|
srslte_ra_ul_grant_fprint(stdout, grant);
|
|
|
|
}
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unpack RAR UL grant as defined in Section 6.2 of 36.213 */
|
|
|
|
void srslte_dci_rar_grant_unpack(srslte_dci_rar_grant_t *rar, uint8_t grant[SRSLTE_RAR_GRANT_LEN])
|
|
|
|
{
|
|
|
|
uint8_t *grant_ptr = grant;
|
|
|
|
rar->hopping_flag = srslte_bit_pack(&grant_ptr, 1)?true:false;
|
|
|
|
rar->rba = srslte_bit_pack(&grant_ptr, 10);
|
|
|
|
rar->trunc_mcs = srslte_bit_pack(&grant_ptr, 4);
|
|
|
|
rar->tpc_pusch = srslte_bit_pack(&grant_ptr, 3);
|
|
|
|
rar->ul_delay = srslte_bit_pack(&grant_ptr, 1)?true:false;
|
|
|
|
rar->cqi_request = srslte_bit_pack(&grant_ptr, 1)?true:false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pack RAR UL grant as defined in Section 6.2 of 36.213 */
|
|
|
|
void srslte_dci_rar_grant_pack(srslte_dci_rar_grant_t *rar, uint8_t grant[SRSLTE_RAR_GRANT_LEN])
|
|
|
|
{
|
|
|
|
uint8_t *grant_ptr = grant;
|
|
|
|
srslte_bit_unpack(rar->hopping_flag?1:0, &grant_ptr, 1);
|
|
|
|
srslte_bit_unpack(rar->rba, &grant_ptr, 10);
|
|
|
|
srslte_bit_unpack(rar->trunc_mcs, &grant_ptr, 4);
|
|
|
|
srslte_bit_unpack(rar->tpc_pusch, &grant_ptr, 3);
|
|
|
|
srslte_bit_unpack(rar->ul_delay?1:0, &grant_ptr, 1);
|
|
|
|
srslte_bit_unpack(rar->cqi_request?1:0, &grant_ptr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void srslte_dci_rar_grant_fprint(FILE *stream, srslte_dci_rar_grant_t *rar) {
|
|
|
|
fprintf(stream, "RBA: %d, MCS: %d, TPC: %d, Hopping=%s, UL-Delay=%s, CQI=%s\n",
|
|
|
|
rar->rba, rar->trunc_mcs, rar->tpc_pusch,
|
|
|
|
rar->hopping_flag?"yes":"no",
|
|
|
|
rar->ul_delay?"yes":"no",
|
|
|
|
rar->cqi_request?"yes":"no"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Creates the UL PUSCH resource allocation grant from a DCI format 0 message
|
|
|
|
*/
|
|
|
|
int srslte_dci_msg_to_ul_grant(srslte_dci_msg_t *msg, uint32_t nof_prb,
|
|
|
|
uint32_t n_rb_ho,
|
|
|
|
srslte_ra_ul_dci_t *ul_dci,
|
|
|
|
srslte_ra_ul_grant_t *grant, uint32_t harq_pid)
|
|
|
|
{
|
|
|
|
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
|
|
|
|
if (msg != NULL &&
|
|
|
|
ul_dci != NULL &&
|
|
|
|
grant != NULL)
|
|
|
|
{
|
|
|
|
ret = SRSLTE_ERROR;
|
|
|
|
|
|
|
|
bzero(ul_dci, sizeof(srslte_ra_ul_dci_t));
|
|
|
|
bzero(grant, sizeof(srslte_ra_ul_grant_t));
|
|
|
|
|
|
|
|
if (srslte_dci_msg_unpack_pusch(msg, ul_dci, nof_prb)) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, harq_pid)) {
|
|
|
|
fprintf(stderr, "Error computing resource allocation\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SRSLTE_VERBOSE_ISINFO()) {
|
|
|
|
srslte_ra_pusch_fprint(stdout, ul_dci, nof_prb);
|
|
|
|
srslte_ra_ul_grant_fprint(stdout, grant);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int srslte_dci_location_set(srslte_dci_location_t *c, uint32_t L, uint32_t nCCE) {
|
|
|
|
if (L <= 3) {
|
|
|
|
c->L = L;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Invalid L %d\n", L);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
if (nCCE <= 87) {
|
|
|
|
c->ncce = nCCE;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool srslte_dci_location_isvalid(srslte_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) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
if (size == ambiguous_sizes[i]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************
|
|
|
|
* PAYLOAD sizeof functions
|
|
|
|
* ********************************/
|
|
|
|
uint32_t dci_format0_sizeof_(uint32_t nof_prb) {
|
|
|
|
return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format1A_sizeof(uint32_t nof_prb) {
|
|
|
|
uint32_t n;
|
|
|
|
n = 1 + 1 + riv_nbits(nof_prb) + 5 + harq_pid_len + 1 + 2 + 2;
|
|
|
|
while (n < dci_format0_sizeof_(nof_prb)) {
|
|
|
|
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);
|
|
|
|
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 / srslte_ra_type0_P(nof_prb)) + 5 + harq_pid_len + 1 + 2
|
|
|
|
+ 2;
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
while (n == dci_format0_sizeof(nof_prb) || n == dci_format1A_sizeof(nof_prb)
|
|
|
|
|| is_ambiguous_size(n)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format1C_sizeof(uint32_t nof_prb) {
|
|
|
|
uint32_t n_vrb_dl_gap1 = srslte_ra_type2_n_vrb_dl(nof_prb, true);
|
|
|
|
uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb);
|
|
|
|
uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5;
|
|
|
|
if (nof_prb >= 50) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Number of TPMI bits
|
|
|
|
uint32_t tpmi_bits(uint32_t nof_ports) {
|
|
|
|
if (nof_ports <= 2) {
|
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format1B_sizeof(uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
// same as format1A minus the differentiation bit plus TPMI + PMI
|
|
|
|
uint32_t n = dci_format1A_sizeof(nof_prb)-1+tpmi_bits(nof_ports)+1;
|
|
|
|
|
|
|
|
while (is_ambiguous_size(n)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format1D_sizeof(uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
// same size as format1B
|
|
|
|
return dci_format1B_sizeof(nof_prb, nof_ports);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Number of bits for precoding information
|
|
|
|
uint32_t precoding_bits_f2(uint32_t nof_ports) {
|
|
|
|
if (nof_ports <= 2) {
|
|
|
|
return 3;
|
|
|
|
} else {
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format2_sizeof(uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2)+precoding_bits_f2(nof_ports);
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
while (is_ambiguous_size(n)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Number of bits for precoding information
|
|
|
|
uint32_t precoding_bits_f2a(uint32_t nof_ports) {
|
|
|
|
if (nof_ports <= 2) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format2A_sizeof(uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2)+precoding_bits_f2a(nof_ports);
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
while (is_ambiguous_size(n)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t dci_format2B_sizeof(uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2);
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
while (is_ambiguous_size(n)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t srslte_dci_format_sizeof(srslte_dci_format_t format, uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
switch (format) {
|
|
|
|
case SRSLTE_DCI_FORMAT0:
|
|
|
|
return dci_format0_sizeof(nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1:
|
|
|
|
return dci_format1_sizeof(nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1A:
|
|
|
|
return dci_format1A_sizeof(nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1C:
|
|
|
|
return dci_format1C_sizeof(nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1B:
|
|
|
|
return dci_format1B_sizeof(nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT1D:
|
|
|
|
return dci_format1D_sizeof(nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT2:
|
|
|
|
return dci_format2_sizeof(nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT2A:
|
|
|
|
return dci_format2A_sizeof(nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT2B:
|
|
|
|
return dci_format2B_sizeof(nof_prb, nof_ports);
|
|
|
|
/*
|
|
|
|
case SRSLTE_DCI_FORMAT3:
|
|
|
|
return dci_format3_sizeof(nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT3A:
|
|
|
|
return dci_format3A_sizeof(nof_prb);
|
|
|
|
*/
|
|
|
|
default:
|
|
|
|
printf("Error computing DCI bits: Unknown format %d\n", format);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t srslte_dci_format_sizeof_lut(srslte_dci_format_t format, uint32_t nof_prb) {
|
|
|
|
if (nof_prb < 101 && format < 4) {
|
|
|
|
return dci_sz_table[nof_prb][format];
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
int dci_format0_pack(srslte_ra_ul_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
uint32_t n_ul_hop;
|
|
|
|
|
|
|
|
*y++ = 0; // format differentiation
|
|
|
|
if (data->freq_hop_fl == SRSLTE_RA_PUSCH_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;
|
|
|
|
if (data->type2_alloc.L_crb) {
|
|
|
|
riv = srslte_ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
|
|
|
|
nof_prb);
|
|
|
|
} else {
|
|
|
|
riv = data->type2_alloc.riv;
|
|
|
|
}
|
|
|
|
|
|
|
|
srslte_bit_unpack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
|
|
|
|
|
|
|
/* pack MCS according to 8.6.1 of 36.213 */
|
|
|
|
srslte_bit_unpack(data->mcs_idx, &y, 5);
|
|
|
|
|
|
|
|
*y++ = data->ndi;
|
|
|
|
|
|
|
|
// TCP command for PUSCH
|
|
|
|
srslte_bit_unpack(data->tpc_pusch, &y, 2);
|
|
|
|
|
|
|
|
// DM RS not implemented
|
|
|
|
srslte_bit_unpack(data->n_dmrs, &y, 3);
|
|
|
|
|
|
|
|
// CQI request
|
|
|
|
*y++ = data->cqi_request;
|
|
|
|
|
|
|
|
// Padding with zeros
|
|
|
|
uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1);
|
|
|
|
while (y - msg->data < n) {
|
|
|
|
*y++ = 0;
|
|
|
|
}
|
|
|
|
msg->nof_bits = (y - msg->data);
|
|
|
|
return SRSLTE_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
|
|
|
|
*/
|
|
|
|
int dci_format0_unpack(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t nof_prb) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
uint32_t n_ul_hop;
|
|
|
|
|
|
|
|
/* Make sure it's a SRSLTE_DCI_FORMAT0 message */
|
|
|
|
if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1)) {
|
|
|
|
fprintf(stderr, "Invalid message length for format 0\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
if (*y++ != 0) {
|
|
|
|
INFO("DCI message is Format1A\n", 0);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
if (*y++ == 0) {
|
|
|
|
data->freq_hop_fl = SRSLTE_RA_PUSCH_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
|
|
|
|
data->freq_hop_fl = y[0] << 1 | y[1];
|
|
|
|
y += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* unpack RIV according to 8.1 of 36.213 */
|
|
|
|
uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - n_ul_hop);
|
|
|
|
srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
|
|
|
|
nof_prb, nof_prb);
|
|
|
|
data->type2_alloc.riv = riv;
|
|
|
|
|
|
|
|
/* unpack MCS according to 8.6 of 36.213 */
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
|
|
|
|
// TPC command for scheduled PUSCH
|
|
|
|
data->tpc_pusch = srslte_bit_pack(&y, 2);
|
|
|
|
|
|
|
|
// Cyclic shift for DMRS
|
|
|
|
data->n_dmrs = srslte_bit_pack(&y, 3);
|
|
|
|
|
|
|
|
// CQI request
|
|
|
|
data->cqi_request = *y++ ? true : false;
|
|
|
|
|
|
|
|
return SRSLTE_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(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
*y++ = data->alloc_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resource allocation: type0 or type 1 */
|
|
|
|
uint32_t P = srslte_ra_type0_P(nof_prb);
|
|
|
|
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
|
|
|
|
switch (data->alloc_type) {
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE0:
|
|
|
|
srslte_bit_unpack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size);
|
|
|
|
break;
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE1:
|
|
|
|
srslte_bit_unpack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
|
|
|
|
*y++ = data->type1_alloc.shift ? 1 : 0;
|
|
|
|
srslte_bit_unpack((uint32_t) data->type1_alloc.vrb_bitmask, &y,
|
|
|
|
alloc_size - (int) ceilf(log2f(P)) - 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr,
|
|
|
|
"Format 1 accepts type0 or type1 resource allocation only\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
/* pack MCS */
|
|
|
|
srslte_bit_unpack(data->mcs_idx, &y, 5);
|
|
|
|
|
|
|
|
/* harq process number */
|
|
|
|
srslte_bit_unpack(data->harq_process, &y, harq_pid_len);
|
|
|
|
|
|
|
|
*y++ = data->ndi;
|
|
|
|
|
|
|
|
// rv version
|
|
|
|
srslte_bit_unpack(data->rv_idx, &y, 2);
|
|
|
|
|
|
|
|
// TCP command for PUCCH
|
|
|
|
srslte_bit_unpack(data->tpc_pucch, &y, 2);
|
|
|
|
|
|
|
|
// Padding with zeros
|
|
|
|
uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1);
|
|
|
|
while (y - msg->data < n) {
|
|
|
|
*y++ = 0;
|
|
|
|
}
|
|
|
|
msg->nof_bits = (y - msg->data);
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
/* Make sure it's a SRSLTE_DCI_FORMAT1 message */
|
|
|
|
if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) {
|
|
|
|
fprintf(stderr, "Invalid message length for format 1\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
data->alloc_type = *y++;
|
|
|
|
} else {
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resource allocation: type0 or type 1 */
|
|
|
|
uint32_t P = srslte_ra_type0_P(nof_prb);
|
|
|
|
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
|
|
|
|
switch (data->alloc_type) {
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE0:
|
|
|
|
data->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size);
|
|
|
|
break;
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE1:
|
|
|
|
data->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int) ceilf(log2f(P)));
|
|
|
|
data->type1_alloc.shift = *y++ ? true : false;
|
|
|
|
data->type1_alloc.vrb_bitmask = srslte_bit_pack(&y,
|
|
|
|
alloc_size - (int) ceilf(log2f(P)) - 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
/* unpack MCS according to 7.1.7 of 36.213 */
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
|
|
|
|
/* harq process number */
|
|
|
|
data->harq_process = srslte_bit_pack(&y, harq_pid_len);
|
|
|
|
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
// rv version
|
|
|
|
data->rv_idx = srslte_bit_pack(&y, 2);
|
|
|
|
|
|
|
|
// TPC not implemented
|
|
|
|
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb,
|
|
|
|
bool crc_is_crnti) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
*y++ = 1; // format differentiation
|
|
|
|
|
|
|
|
if (data->alloc_type != SRSLTE_RA_ALLOC_TYPE2) {
|
|
|
|
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->dci_is_1a = true;
|
|
|
|
|
|
|
|
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
|
|
|
|
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) {
|
|
|
|
if (data->type2_alloc.L_crb > nof_prb) {
|
|
|
|
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n",
|
|
|
|
data->type2_alloc.L_crb);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
uint32_t n_vrb_dl;
|
|
|
|
if (crc_is_crnti && nof_prb > 50) {
|
|
|
|
n_vrb_dl = 16;
|
|
|
|
} else {
|
|
|
|
n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
}
|
|
|
|
if (data->type2_alloc.L_crb > n_vrb_dl) {
|
|
|
|
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 SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* pack RIV according to 7.1.6.3 of 36.213 */
|
|
|
|
uint32_t riv;
|
|
|
|
if (data->type2_alloc.L_crb) {
|
|
|
|
riv = srslte_ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
|
|
|
|
nof_prb);
|
|
|
|
} else {
|
|
|
|
riv = data->type2_alloc.riv;
|
|
|
|
}
|
|
|
|
uint32_t nb_gap = 0;
|
|
|
|
if (crc_is_crnti && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) {
|
|
|
|
nb_gap = 1;
|
|
|
|
*y++ = data->type2_alloc.n_gap;
|
|
|
|
}
|
|
|
|
srslte_bit_unpack(riv, &y, riv_nbits(nof_prb) - nb_gap);
|
|
|
|
|
|
|
|
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
|
|
|
|
srslte_bit_unpack(data->mcs_idx, &y, 5);
|
|
|
|
|
|
|
|
srslte_bit_unpack(data->harq_process, &y, harq_pid_len);
|
|
|
|
|
|
|
|
if (crc_is_crnti) {
|
|
|
|
if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) {
|
|
|
|
*y++ = data->type2_alloc.n_gap;
|
|
|
|
} else {
|
|
|
|
y++; // bit reserved
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*y++ = data->ndi;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rv version
|
|
|
|
srslte_bit_unpack(data->rv_idx, &y, 2);
|
|
|
|
|
|
|
|
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 = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1);
|
|
|
|
while (y - msg->data < n) {
|
|
|
|
*y++ = 0;
|
|
|
|
}
|
|
|
|
msg->nof_bits = (y - msg->data);
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb,
|
|
|
|
bool crc_is_crnti) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
/* Make sure it's a SRSLTE_DCI_FORMAT0 message */
|
|
|
|
if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) {
|
|
|
|
fprintf(stderr, "Invalid message length for format 1A\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*y++ != 1) {
|
|
|
|
INFO("DCI message is Format0\n", 0);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->dci_is_1a = true;
|
|
|
|
|
|
|
|
// Check if RA procedure by PDCCH order
|
|
|
|
if (*y == 0) {
|
|
|
|
int nof_bits = riv_nbits(nof_prb);
|
|
|
|
int i=0;
|
|
|
|
while(i<nof_bits && y[1+i] == 1)
|
|
|
|
i++;
|
|
|
|
if (i == nof_bits) {
|
|
|
|
//printf("Warning check me: could this be a RA PDCCH order??\n");
|
|
|
|
i=1+10+nof_bits;
|
|
|
|
while(i<msg->nof_bits-1 && y[i] == 0) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i == msg->nof_bits-1) {
|
|
|
|
//printf("Received a Format1A RA PDCCH order. Not implemented!\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE2;
|
|
|
|
data->type2_alloc.mode = *y++;
|
|
|
|
|
|
|
|
// by default, set N_gap to 1
|
|
|
|
data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1;
|
|
|
|
|
|
|
|
/* unpack RIV according to 7.1.6.3 of 36.213 */
|
|
|
|
uint32_t nb_gap = 0;
|
|
|
|
if (crc_is_crnti && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) {
|
|
|
|
nb_gap = 1;
|
|
|
|
data->type2_alloc.n_gap = *y++;
|
|
|
|
}
|
|
|
|
uint32_t nof_vrb;
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) {
|
|
|
|
nof_vrb = nof_prb;
|
|
|
|
} else {
|
|
|
|
nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
}
|
|
|
|
uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap);
|
|
|
|
srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
|
|
|
|
nof_prb, nof_vrb);
|
|
|
|
data->type2_alloc.riv = riv;
|
|
|
|
|
|
|
|
// unpack MCS
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
|
|
|
|
data->harq_process = srslte_bit_pack(&y, harq_pid_len);
|
|
|
|
|
|
|
|
if (!crc_is_crnti) {
|
|
|
|
if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) {
|
|
|
|
data->type2_alloc.n_gap = *y++;
|
|
|
|
} else {
|
|
|
|
y++; // NDI reserved
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rv version
|
|
|
|
data->rv_idx = srslte_bit_pack(&y, 2);
|
|
|
|
|
|
|
|
if (crc_is_crnti) {
|
|
|
|
// TPC not implemented
|
|
|
|
y++;
|
|
|
|
y++;
|
|
|
|
} else {
|
|
|
|
y++; // MSB of TPC is reserved
|
|
|
|
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
|
|
|
|
}
|
|
|
|
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dci_format1B_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE2;
|
|
|
|
data->type2_alloc.mode = *y++;
|
|
|
|
|
|
|
|
// by default, set N_gap to 1
|
|
|
|
data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1;
|
|
|
|
|
|
|
|
/* unpack RIV according to 7.1.6.3 of 36.213 */
|
|
|
|
uint32_t nb_gap = 0;
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) {
|
|
|
|
nb_gap = 1;
|
|
|
|
data->type2_alloc.n_gap = *y++;
|
|
|
|
}
|
|
|
|
uint32_t nof_vrb;
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) {
|
|
|
|
nof_vrb = nof_prb;
|
|
|
|
} else {
|
|
|
|
nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
}
|
|
|
|
uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap);
|
|
|
|
srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
|
|
|
|
nof_prb, nof_vrb);
|
|
|
|
data->type2_alloc.riv = riv;
|
|
|
|
|
|
|
|
// unpack MCS, Harq pid and ndi
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
data->harq_process = srslte_bit_pack(&y, harq_pid_len);
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
data->rv_idx = srslte_bit_pack(&y, 2);
|
|
|
|
|
|
|
|
// Ignore TPC command for PUCCH
|
|
|
|
y += 2;
|
|
|
|
|
|
|
|
data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports));
|
|
|
|
data->pconf = *y++ ? true : false;
|
|
|
|
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Format 1C for compact scheduling of PDSCH words
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int dci_format1Cs_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
if (data->alloc_type != SRSLTE_RA_ALLOC_TYPE2 || data->type2_alloc.mode != SRSLTE_RA_TYPE2_DIST) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Format 1C accepts distributed type2 resource allocation only\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->dci_is_1c = true;
|
|
|
|
|
|
|
|
if (nof_prb >= 50) {
|
|
|
|
*y++ = data->type2_alloc.n_gap;
|
|
|
|
}
|
|
|
|
uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb);
|
|
|
|
uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
|
|
|
|
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 SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
if (data->type2_alloc.L_crb % n_step) {
|
|
|
|
fprintf(stderr, "L_crb must be multiple of n_step\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
if (data->type2_alloc.RB_start % n_step) {
|
|
|
|
fprintf(stderr, "RB_start must be multiple of n_step\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
|
|
uint32_t riv;
|
|
|
|
if (data->type2_alloc.L_crb) {
|
|
|
|
riv = srslte_ra_type2_to_riv(L_p, RB_p, n_vrb_p);
|
|
|
|
} else {
|
|
|
|
riv = data->type2_alloc.riv;
|
|
|
|
}
|
|
|
|
srslte_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
|
|
|
|
srslte_bit_unpack(data->mcs_idx, &y, 5);
|
|
|
|
|
|
|
|
msg->nof_bits = (y - msg->data);
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dci_format1Cs_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb) {
|
|
|
|
uint32_t L_p, RB_p;
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) {
|
|
|
|
fprintf(stderr, "Invalid message length for format 1C\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->dci_is_1c = true;
|
|
|
|
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE2;
|
|
|
|
data->type2_alloc.mode = SRSLTE_RA_TYPE2_DIST;
|
|
|
|
if (nof_prb >= 50) {
|
|
|
|
data->type2_alloc.n_gap = *y++;
|
|
|
|
}
|
|
|
|
uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb);
|
|
|
|
uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
|
|
|
|
uint32_t riv = srslte_bit_pack(&y, riv_nbits((int) n_vrb_dl / n_step));
|
|
|
|
uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step;
|
|
|
|
|
|
|
|
srslte_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 = srslte_bit_pack(&y, 5);
|
|
|
|
|
|
|
|
data->rv_idx = -1; // Get RV later
|
|
|
|
|
|
|
|
msg->nof_bits = (y - msg->data);
|
|
|
|
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dci_format1D_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE2;
|
|
|
|
data->type2_alloc.mode = *y++;
|
|
|
|
|
|
|
|
// by default, set N_gap to 1
|
|
|
|
data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1;
|
|
|
|
|
|
|
|
/* unpack RIV according to 7.1.6.3 of 36.213 */
|
|
|
|
uint32_t nb_gap = 0;
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) {
|
|
|
|
nb_gap = 1;
|
|
|
|
data->type2_alloc.n_gap = *y++;
|
|
|
|
}
|
|
|
|
uint32_t nof_vrb;
|
|
|
|
if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) {
|
|
|
|
nof_vrb = nof_prb;
|
|
|
|
} else {
|
|
|
|
nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1);
|
|
|
|
}
|
|
|
|
uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap);
|
|
|
|
srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
|
|
|
|
nof_prb, nof_vrb);
|
|
|
|
data->type2_alloc.riv = riv;
|
|
|
|
|
|
|
|
// unpack MCS, Harq pid and ndi
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
data->harq_process = srslte_bit_pack(&y, harq_pid_len);
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
data->rv_idx = srslte_bit_pack(&y, 2);
|
|
|
|
|
|
|
|
// Ignore TPC command for PUCCH
|
|
|
|
y += 2;
|
|
|
|
|
|
|
|
data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports));
|
|
|
|
data->power_offset = *y++ ? true : false;
|
|
|
|
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports) {
|
|
|
|
|
|
|
|
/* pack bits */
|
|
|
|
uint8_t *y = msg->data;
|
|
|
|
|
|
|
|
if (nof_prb > 10) {
|
|
|
|
data->alloc_type = *y++;
|
|
|
|
} else {
|
|
|
|
data->alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resource allocation: type0 or type 1 */
|
|
|
|
uint32_t P = srslte_ra_type0_P(nof_prb);
|
|
|
|
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
|
|
|
|
switch (data->alloc_type) {
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE0:
|
|
|
|
data->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size);
|
|
|
|
break;
|
|
|
|
case SRSLTE_RA_ALLOC_TYPE1:
|
|
|
|
data->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int) ceilf(log2f(P)));
|
|
|
|
data->type1_alloc.shift = *y++ ? true : false;
|
|
|
|
data->type1_alloc.vrb_bitmask = srslte_bit_pack(&y,
|
|
|
|
alloc_size - (int) ceilf(log2f(P)) - 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Format2 accepts type0 or type1 resource allocation only\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
// unpack TPC command for PUCCH (not implemented)
|
|
|
|
y+=2;
|
|
|
|
|
|
|
|
/* harq process number */
|
|
|
|
data->harq_process = srslte_bit_pack(&y, harq_pid_len);
|
|
|
|
|
|
|
|
// Transpor block to codeword swap flag
|
|
|
|
if (msg->format == SRSLTE_DCI_FORMAT2B) {
|
|
|
|
data->sram_id = *y++ ? true : false;
|
|
|
|
} else {
|
|
|
|
data->tb_cw_swap = *y++ ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unpack MCS according to 7.1.7 of 36.213 */
|
|
|
|
data->mcs_idx = srslte_bit_pack(&y, 5);
|
|
|
|
data->ndi = *y++ ? true : false;
|
|
|
|
data->rv_idx = srslte_bit_pack(&y, 2);
|
|
|
|
if (data->mcs_idx == 0 && data->rv_idx == 1) {
|
|
|
|
data->tb_en[0] = false;
|
|
|
|
} else {
|
|
|
|
data->tb_en[0] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// same for tb1
|
|
|
|
data->mcs_idx_1 = srslte_bit_pack(&y, 5);
|
|
|
|
data->ndi_1 = *y++ ? true : false;
|
|
|
|
data->rv_idx_1 = srslte_bit_pack(&y, 2);
|
|
|
|
if (data->mcs_idx_1 == 0 && data->rv_idx_1 == 1) {
|
|
|
|
data->tb_en[1] = false;
|
|
|
|
} else {
|
|
|
|
data->tb_en[1] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Precoding information
|
|
|
|
if (msg->format == SRSLTE_DCI_FORMAT2A) {
|
|
|
|
data->pinfo = srslte_bit_pack(&y, precoding_bits_f2(nof_ports));
|
|
|
|
} else if (msg->format == SRSLTE_DCI_FORMAT2A) {
|
|
|
|
data->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(nof_ports));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_dci_msg_pack_pdsch(srslte_ra_dl_dci_t *data, srslte_dci_format_t format,
|
|
|
|
srslte_dci_msg_t *msg, uint32_t nof_prb,
|
|
|
|
bool crc_is_crnti)
|
|
|
|
{
|
|
|
|
msg->format = format;
|
|
|
|
switch (format) {
|
|
|
|
case SRSLTE_DCI_FORMAT1:
|
|
|
|
return dci_format1_pack(data, msg, nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1A:
|
|
|
|
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
|
|
|
|
case SRSLTE_DCI_FORMAT1C:
|
|
|
|
return dci_format1Cs_pack(data, msg, nof_prb);
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "DCI pack pdsch: Invalid DCI format %s in \n",
|
|
|
|
srslte_dci_format_string(format));
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int srslte_dci_msg_unpack_pdsch(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data,
|
|
|
|
uint32_t nof_prb, uint32_t nof_ports, bool crc_is_crnti)
|
|
|
|
{
|
|
|
|
switch (msg->format) {
|
|
|
|
case SRSLTE_DCI_FORMAT1:
|
|
|
|
return dci_format1_unpack(msg, data, nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1A:
|
|
|
|
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
|
|
|
|
case SRSLTE_DCI_FORMAT1B:
|
|
|
|
return dci_format1B_unpack(msg, data, nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT1C:
|
|
|
|
return dci_format1Cs_unpack(msg, data, nof_prb);
|
|
|
|
case SRSLTE_DCI_FORMAT1D:
|
|
|
|
return dci_format1D_unpack(msg, data, nof_prb, nof_ports);
|
|
|
|
case SRSLTE_DCI_FORMAT2:
|
|
|
|
case SRSLTE_DCI_FORMAT2A:
|
|
|
|
case SRSLTE_DCI_FORMAT2B:
|
|
|
|
return dci_format2AB_unpack(msg, data, nof_prb, nof_ports);
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "DCI unpack pdsch: Invalid DCI format %s\n",
|
|
|
|
srslte_dci_format_string(msg->format));
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int srslte_dci_msg_pack_pusch(srslte_ra_ul_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) {
|
|
|
|
return dci_format0_pack(data, msg, nof_prb);
|
|
|
|
}
|
|
|
|
|
|
|
|
int srslte_dci_msg_unpack_pusch(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t nof_prb) {
|
|
|
|
return dci_format0_unpack(msg, data, nof_prb);
|
|
|
|
}
|
|
|
|
|
|
|
|
srslte_dci_format_t srslte_dci_format_from_string(char *str) {
|
|
|
|
if (!strcmp(str, "Format0")) {
|
|
|
|
return SRSLTE_DCI_FORMAT0;
|
|
|
|
} else if (!strcmp(str, "Format1")) {
|
|
|
|
return SRSLTE_DCI_FORMAT1;
|
|
|
|
} else if (!strcmp(str, "Format1A")) {
|
|
|
|
return SRSLTE_DCI_FORMAT1A;
|
|
|
|
} else if (!strcmp(str, "Format1B")) {
|
|
|
|
return SRSLTE_DCI_FORMAT1B;
|
|
|
|
} else if (!strcmp(str, "Format1C")) {
|
|
|
|
return SRSLTE_DCI_FORMAT1C;
|
|
|
|
} else if (!strcmp(str, "Format1D")) {
|
|
|
|
return SRSLTE_DCI_FORMAT1D;
|
|
|
|
} else if (!strcmp(str, "Format2")) {
|
|
|
|
return SRSLTE_DCI_FORMAT2;
|
|
|
|
} else if (!strcmp(str, "Format2A")) {
|
|
|
|
return SRSLTE_DCI_FORMAT2A;
|
|
|
|
} else if (!strcmp(str, "Format2B")) {
|
|
|
|
return SRSLTE_DCI_FORMAT2B;
|
|
|
|
} else {
|
|
|
|
return SRSLTE_DCI_NOF_FORMATS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char* srslte_dci_format_string(srslte_dci_format_t format) {
|
|
|
|
switch (format) {
|
|
|
|
case SRSLTE_DCI_FORMAT0:
|
|
|
|
return "Format0 ";
|
|
|
|
case SRSLTE_DCI_FORMAT1:
|
|
|
|
return "Format1 ";
|
|
|
|
case SRSLTE_DCI_FORMAT1A:
|
|
|
|
return "Format1A";
|
|
|
|
case SRSLTE_DCI_FORMAT1B:
|
|
|
|
return "Format1B";
|
|
|
|
case SRSLTE_DCI_FORMAT1C:
|
|
|
|
return "Format1C";
|
|
|
|
case SRSLTE_DCI_FORMAT1D:
|
|
|
|
return "Format1D";
|
|
|
|
case SRSLTE_DCI_FORMAT2:
|
|
|
|
return "Format2 ";
|
|
|
|
case SRSLTE_DCI_FORMAT2A:
|
|
|
|
return "Format2A";
|
|
|
|
case SRSLTE_DCI_FORMAT2B:
|
|
|
|
return "Format2B";
|
|
|
|
default:
|
|
|
|
return "N/A"; // fatal error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void srslte_dci_msg_type_fprint(FILE *f, srslte_dci_msg_type_t type) {
|
|
|
|
switch (type.type) {
|
|
|
|
case SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED:
|
|
|
|
fprintf(f, "%s PUSCH Scheduling\n", srslte_dci_format_string(type.format));
|
|
|
|
break;
|
|
|
|
case SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED:
|
|
|
|
fprintf(f, "%s PDSCH Scheduling\n", srslte_dci_format_string(type.format));
|
|
|
|
break;
|
|
|
|
case SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH:
|
|
|
|
fprintf(f, "%s Random access initiated by PDCCH\n",
|
|
|
|
srslte_dci_format_string(type.format));
|
|
|
|
break;
|
|
|
|
case SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE:
|
|
|
|
fprintf(f, "%s MCCH change notification\n", srslte_dci_format_string(type.format));
|
|
|
|
break;
|
|
|
|
case SRSLTE_DCI_MSG_TYPE_TPC_COMMAND:
|
|
|
|
fprintf(f, "%s TPC command\n", srslte_dci_format_string(type.format));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Warning this function will be deprecated. Currently only used in test programs */
|
|
|
|
int srslte_dci_msg_get_type(srslte_dci_msg_t *msg, srslte_dci_msg_type_t *type, uint32_t nof_prb,
|
|
|
|
uint16_t msg_rnti)
|
|
|
|
{
|
|
|
|
DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x\n", msg->nof_bits, msg_rnti);
|
|
|
|
if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1)
|
|
|
|
&& !msg->data[0]) {
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED;
|
|
|
|
type->format = SRSLTE_DCI_FORMAT0;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
} else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) {
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported
|
|
|
|
type->format = SRSLTE_DCI_FORMAT1;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
} else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) {
|
|
|
|
/* The RNTI is not the only condition. Also some fields in the packet.
|
|
|
|
* if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) {
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH;
|
|
|
|
type->format = SRSLTE_DCI_FORMAT1A;
|
|
|
|
} else {
|
|
|
|
*/
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported
|
|
|
|
type->format = SRSLTE_DCI_FORMAT1A;
|
|
|
|
//}
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
} else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) {
|
|
|
|
if (msg_rnti == SRSLTE_MRNTI) {
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE;
|
|
|
|
type->format = SRSLTE_DCI_FORMAT1C;
|
|
|
|
} else {
|
|
|
|
type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported
|
|
|
|
type->format = SRSLTE_DCI_FORMAT1C;
|
|
|
|
}
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
|