|
|
|
@ -49,14 +49,6 @@
|
|
|
|
|
|
|
|
|
|
#define MIN(a,b) ((a>b)?b:a)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define NOF_COMMON_FORMATS 2
|
|
|
|
|
const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C };
|
|
|
|
|
|
|
|
|
|
#define NOF_UE_FORMATS 2
|
|
|
|
|
const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void set_cfi(pdcch_t *q, uint32_t cfi) {
|
|
|
|
|
if (cfi > 0 && cfi < 4) {
|
|
|
|
|
q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9;
|
|
|
|
@ -83,10 +75,11 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) {
|
|
|
|
|
fprintf(stderr, "Error initializing precoding\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate memory for the largest aggregation level L=3 */
|
|
|
|
|
q->max_bits = PDCCH_FORMAT_NOF_BITS(3);
|
|
|
|
|
/* Allocate memory for the maximum number of PDCCH bits (CFI=3) */
|
|
|
|
|
q->max_bits = (regs_pdcch_nregs(q->regs, 3) / 9) * 72;
|
|
|
|
|
|
|
|
|
|
INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports);
|
|
|
|
|
INFO("Init PDCCH: Max bits: %d, %d ports.\n",
|
|
|
|
|
q->max_bits, q->cell.nof_ports);
|
|
|
|
|
|
|
|
|
|
if (modem_table_lte(&q->mod, LTE_QPSK, true)) {
|
|
|
|
|
goto clean;
|
|
|
|
@ -112,31 +105,33 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pdcch_e = malloc(sizeof(uint8_t) * q->max_bits);
|
|
|
|
|
q->pdcch_e = vec_malloc(sizeof(uint8_t) * q->max_bits);
|
|
|
|
|
if (!q->pdcch_e) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pdcch_llr = malloc(sizeof(float) * q->max_bits);
|
|
|
|
|
q->pdcch_llr = vec_malloc(sizeof(float) * q->max_bits);
|
|
|
|
|
if (!q->pdcch_llr) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pdcch_d = malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
bzero(q->pdcch_llr, sizeof(float) * q->max_bits);
|
|
|
|
|
|
|
|
|
|
q->pdcch_d = vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
if (!q->pdcch_d) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PORTS; i++) {
|
|
|
|
|
q->ce[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
q->ce[i] = vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
if (!q->ce[i]) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
q->pdcch_x[i] = vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
if (!q->pdcch_x[i]) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
|
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
q->pdcch_symbols[i] = vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
|
|
|
|
if (!q->pdcch_symbols[i]) {
|
|
|
|
|
goto clean;
|
|
|
|
|
}
|
|
|
|
@ -204,7 +199,7 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat
|
|
|
|
|
|
|
|
|
|
// Compute Yk for this subframe
|
|
|
|
|
Yk = rnti;
|
|
|
|
|
for (m = 0; m < nsubframe; m++) {
|
|
|
|
|
for (m = 0; m < nsubframe+1; m++) {
|
|
|
|
|
Yk = (39827 * Yk) % 65537;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -213,7 +208,7 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat
|
|
|
|
|
for (l = 3; l >= 0; l--) {
|
|
|
|
|
L = (1 << l);
|
|
|
|
|
// For all possible ncce offset
|
|
|
|
|
for (i = 0; i < MIN(q->nof_cce / L, 16 / S[l]); i++) {
|
|
|
|
|
for (i = 0; i < MIN(q->nof_cce / L, S[l]/PDCCH_FORMAT_NOF_CCE(l)); i++) {
|
|
|
|
|
ncce = L * ((Yk + i) % (q->nof_cce / L));
|
|
|
|
|
if (k < max_candidates &&
|
|
|
|
|
ncce + PDCCH_FORMAT_NOF_CCE(l) <= q->nof_cce)
|
|
|
|
@ -221,7 +216,7 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat
|
|
|
|
|
c[k].L = l;
|
|
|
|
|
c[k].ncce = ncce;
|
|
|
|
|
|
|
|
|
|
DEBUG("UE-specific SS Candidate %d: nCCE: %d, L: %d\n",
|
|
|
|
|
INFO("UE-specific SS Candidate %d: nCCE: %d, L: %d\n",
|
|
|
|
|
k, c[k].ncce, c[k].L);
|
|
|
|
|
|
|
|
|
|
k++;
|
|
|
|
@ -256,7 +251,7 @@ uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_cand
|
|
|
|
|
if (k < max_candidates) {
|
|
|
|
|
c[k].L = l;
|
|
|
|
|
c[k].ncce = (L) * (i % (q->nof_cce / (L)));
|
|
|
|
|
DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n",
|
|
|
|
|
INFO("Common SS Candidate %d: nCCE: %d, L: %d\n",
|
|
|
|
|
k, c[k].ncce, c[k].L);
|
|
|
|
|
k++;
|
|
|
|
|
}
|
|
|
|
@ -291,6 +286,11 @@ static int dci_decode(pdcch_t *q, float *e, uint8_t *data, uint32_t E, uint32_t
|
|
|
|
|
nof_bits <= DCI_MAX_BITS)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
DEBUG("Rm input: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_f(stdout, e, E);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* unrate matching */
|
|
|
|
|
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
|
|
|
|
|
|
|
|
|
@ -309,7 +309,7 @@ static int dci_decode(pdcch_t *q, float *e, uint8_t *data, uint32_t E, uint32_t
|
|
|
|
|
x = &data[nof_bits];
|
|
|
|
|
p_bits = (uint16_t) bit_unpack(&x, 16);
|
|
|
|
|
crc_res = ((uint16_t) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
|
|
|
|
DEBUG("p_bits: 0x%x, crc_checksum: 0x%x, crc_rem: 0x%x\n", p_bits, crc_res,
|
|
|
|
|
INFO("p_bits: 0x%x, crc_checksum: 0x%x, crc_rem: 0x%x\n", p_bits, crc_res,
|
|
|
|
|
p_bits ^ crc_res);
|
|
|
|
|
|
|
|
|
|
if (crc) {
|
|
|
|
@ -327,18 +327,30 @@ static int dci_decode(pdcch_t *q, float *e, uint8_t *data, uint32_t E, uint32_t
|
|
|
|
|
* The decoded message is stored in msg and the CRC remainder in crc_rem pointer
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *crc_rem)
|
|
|
|
|
int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_location_t *location, dci_format_t format, uint16_t *crc_rem)
|
|
|
|
|
{
|
|
|
|
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
|
|
|
|
if (q != NULL &&
|
|
|
|
|
msg != NULL &&
|
|
|
|
|
if (q != NULL &&
|
|
|
|
|
msg != NULL &&
|
|
|
|
|
dci_location_isvalid(location) &&
|
|
|
|
|
crc_rem != NULL)
|
|
|
|
|
{
|
|
|
|
|
uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb);
|
|
|
|
|
if (location->ncce * 72 + PDCCH_FORMAT_NOF_BITS(location->L) >
|
|
|
|
|
q->nof_cce*72) {
|
|
|
|
|
fprintf(stderr, "Invalid location: nCCE: %d, L: %d, NofCCE: %d\n",
|
|
|
|
|
location->ncce, location->L, q->nof_cce);
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb);
|
|
|
|
|
uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(location->L);
|
|
|
|
|
|
|
|
|
|
ret = dci_decode(q, q->pdcch_llr, msg->data, q->e_bits, nof_bits, crc_rem);
|
|
|
|
|
if (ret == LIBLTE_SUCCESS) {
|
|
|
|
|
msg->nof_bits = nof_bits;
|
|
|
|
|
INFO("Decoding DCI offset %d, e_bits: %d, msg_len %d (nCCE: %d, L: %d)\n",
|
|
|
|
|
location->ncce * 72, e_bits, nof_bits, location->ncce, location->L);
|
|
|
|
|
|
|
|
|
|
ret = dci_decode(q, &q->pdcch_llr[location->ncce * 72],
|
|
|
|
|
msg->data, e_bits, nof_bits, crc_rem);
|
|
|
|
|
if (ret == LIBLTE_SUCCESS) {
|
|
|
|
|
msg->nof_bits = nof_bits;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
@ -350,7 +362,7 @@ int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *
|
|
|
|
|
* new messages from other locations can be decoded
|
|
|
|
|
*/
|
|
|
|
|
int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate,
|
|
|
|
|
dci_location_t location, uint32_t nsubframe, uint32_t cfi) {
|
|
|
|
|
uint32_t nsubframe, uint32_t cfi) {
|
|
|
|
|
|
|
|
|
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
|
|
|
|
|
|
|
|
@ -361,74 +373,66 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float n
|
|
|
|
|
if (q != NULL &&
|
|
|
|
|
nsubframe < 10 &&
|
|
|
|
|
cfi > 0 &&
|
|
|
|
|
cfi < 4 &&
|
|
|
|
|
dci_location_isvalid(&location))
|
|
|
|
|
cfi < 4)
|
|
|
|
|
{
|
|
|
|
|
set_cfi(q, cfi);
|
|
|
|
|
|
|
|
|
|
q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L);
|
|
|
|
|
nof_symbols = q->e_bits/2;
|
|
|
|
|
uint32_t e_bits = 72*q->nof_cce;
|
|
|
|
|
nof_symbols = e_bits/2;
|
|
|
|
|
ret = LIBLTE_ERROR;
|
|
|
|
|
|
|
|
|
|
if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce) {
|
|
|
|
|
INFO("Extracting LLRs: E: %d, SF: %d, CFI: %d\n",
|
|
|
|
|
e_bits, nsubframe, cfi);
|
|
|
|
|
|
|
|
|
|
INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d, SF: %d, CFI: %d\n",
|
|
|
|
|
q->e_bits, location.ncce, location.L, nsubframe, cfi);
|
|
|
|
|
/* number of layers equals number of ports */
|
|
|
|
|
for (i = 0; i < q->cell.nof_ports; i++) {
|
|
|
|
|
x[i] = q->pdcch_x[i];
|
|
|
|
|
}
|
|
|
|
|
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
|
|
|
|
|
|
|
|
|
/* number of layers equals number of ports */
|
|
|
|
|
for (i = 0; i < q->cell.nof_ports; i++) {
|
|
|
|
|
x[i] = q->pdcch_x[i];
|
|
|
|
|
}
|
|
|
|
|
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
|
|
|
|
/* extract symbols */
|
|
|
|
|
int n = regs_pdcch_get(q->regs, sf_symbols, q->pdcch_symbols[0]);
|
|
|
|
|
if (nof_symbols != n) {
|
|
|
|
|
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* extract symbols */
|
|
|
|
|
int n = regs_pdcch_get_offset(q->regs, sf_symbols, q->pdcch_symbols[0],
|
|
|
|
|
location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L));
|
|
|
|
|
/* extract channel estimates */
|
|
|
|
|
for (i = 0; i < q->cell.nof_ports; i++) {
|
|
|
|
|
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
|
|
|
|
|
if (nof_symbols != n) {
|
|
|
|
|
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* extract channel estimates */
|
|
|
|
|
for (i = 0; i < q->cell.nof_ports; i++) {
|
|
|
|
|
n = regs_pdcch_get_offset(q->regs, ce[i], q->ce[i],
|
|
|
|
|
location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L));
|
|
|
|
|
if (nof_symbols != n) {
|
|
|
|
|
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* in control channels, only diversity is supported */
|
|
|
|
|
if (q->cell.nof_ports == 1) {
|
|
|
|
|
/* no need for layer demapping */
|
|
|
|
|
predecoding_single(&q->precoding, q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols, noise_estimate);
|
|
|
|
|
} else {
|
|
|
|
|
predecoding_diversity(&q->precoding, q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols, noise_estimate);
|
|
|
|
|
layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG("pdcch d symbols: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_c(stdout, q->pdcch_d, nof_symbols);
|
|
|
|
|
}
|
|
|
|
|
/* in control channels, only diversity is supported */
|
|
|
|
|
if (q->cell.nof_ports == 1) {
|
|
|
|
|
/* no need for layer demapping */
|
|
|
|
|
predecoding_single(&q->precoding, q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols, noise_estimate);
|
|
|
|
|
} else {
|
|
|
|
|
predecoding_diversity(&q->precoding, q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols, noise_estimate);
|
|
|
|
|
layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* demodulate symbols */
|
|
|
|
|
demod_soft_sigma_set(&q->demod, 1.0);
|
|
|
|
|
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols);
|
|
|
|
|
DEBUG("pdcch d symbols: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_c(stdout, q->pdcch_d, nof_symbols);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG("llr: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_f(stdout, q->pdcch_llr, q->e_bits);
|
|
|
|
|
}
|
|
|
|
|
/* demodulate symbols */
|
|
|
|
|
demod_soft_sigma_set(&q->demod, 1);
|
|
|
|
|
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols);
|
|
|
|
|
|
|
|
|
|
/* descramble */
|
|
|
|
|
scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 72 * location.ncce, q->e_bits);
|
|
|
|
|
/* descramble */
|
|
|
|
|
scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 0, e_bits);
|
|
|
|
|
|
|
|
|
|
ret = LIBLTE_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce);
|
|
|
|
|
DEBUG("llr: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_f(stdout, q->pdcch_llr, e_bits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = LIBLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
@ -514,17 +518,17 @@ int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t r
|
|
|
|
|
|
|
|
|
|
set_cfi(q, cfi);
|
|
|
|
|
|
|
|
|
|
q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L);
|
|
|
|
|
nof_symbols = q->e_bits/2;
|
|
|
|
|
uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(location.L);
|
|
|
|
|
nof_symbols = e_bits/2;
|
|
|
|
|
ret = LIBLTE_ERROR;
|
|
|
|
|
|
|
|
|
|
if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce &&
|
|
|
|
|
msg->nof_bits < DCI_MAX_BITS)
|
|
|
|
|
{
|
|
|
|
|
INFO("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
|
|
|
|
msg->nof_bits, q->e_bits, location.ncce, location.L, rnti);
|
|
|
|
|
msg->nof_bits, e_bits, location.ncce, location.L, rnti);
|
|
|
|
|
|
|
|
|
|
dci_encode(q, msg->data, q->pdcch_e, msg->nof_bits, q->e_bits, rnti);
|
|
|
|
|
dci_encode(q, msg->data, q->pdcch_e, msg->nof_bits, e_bits, rnti);
|
|
|
|
|
|
|
|
|
|
/* number of layers equals number of ports */
|
|
|
|
|
for (i = 0; i < q->cell.nof_ports; i++) {
|
|
|
|
@ -532,14 +536,14 @@ int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t r
|
|
|
|
|
}
|
|
|
|
|
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
|
|
|
|
|
|
|
|
|
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, q->e_bits);
|
|
|
|
|
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, e_bits);
|
|
|
|
|
|
|
|
|
|
DEBUG("Scrambling output: ", 0);
|
|
|
|
|
if (VERBOSE_ISDEBUG()) {
|
|
|
|
|
vec_fprint_b(stdout, q->pdcch_e, q->e_bits);
|
|
|
|
|
vec_fprint_b(stdout, q->pdcch_e, e_bits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits);
|
|
|
|
|
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, e_bits);
|
|
|
|
|
|
|
|
|
|
/* layer mapping & precoding */
|
|
|
|
|
if (q->cell.nof_ports > 1) {
|
|
|
|
|