srsLTE/srslte/lib/phch/pbch.c

579 lines
16 KiB
C
Raw Normal View History

/**
*
* \section COPYRIGHT
*
2015-11-13 04:22:33 -08:00
* 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
2015-05-08 08:05:40 -07:00
* 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
2015-05-08 08:05:40 -07:00
* GNU Affero General Public License for more details.
*
2015-05-08 08:05:40 -07:00
* 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 "prb_dl.h"
#include "srslte/phch/pbch.h"
#include "srslte/common/phy_common.h"
#include "srslte/utils/bit.h"
#include "srslte/utils/vector.h"
#include "srslte/utils/debug.h"
#define PBCH_RE_CP_NORM 240
#define PBCH_RE_CP_EXT 216
2015-03-18 08:05:38 -07:00
const uint8_t srslte_crc_mask[4][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 } };
2015-03-18 11:14:24 -07:00
bool srslte_pbch_exists(int nframe, int nslot) {
2014-06-17 02:11:41 -07:00
return (!(nframe % 5) && nslot == 1);
}
cf_t *offset_original;
2015-03-18 11:14:24 -07:00
int srslte_pbch_cp(cf_t *input, cf_t *output, srslte_cell_t cell, bool put) {
2014-06-17 02:11:41 -07:00
int i;
cf_t *ptr;
offset_original = input;
2014-06-17 02:11:41 -07:00
if (put) {
ptr = input;
2015-03-18 05:59:29 -07:00
output += cell.nof_prb * SRSLTE_NRE / 2 - 36;
2014-06-17 02:11:41 -07:00
} else {
ptr = output;
2015-03-18 05:59:29 -07:00
input += cell.nof_prb * SRSLTE_NRE / 2 - 36;
2014-06-17 02:11:41 -07:00
}
2014-06-17 02:11:41 -07:00
/* symbol 0 & 1 */
2014-06-17 07:32:19 -07:00
for (i = 0; i < 2; i++) {
prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
if (put) {
2015-03-18 05:59:29 -07:00
output += cell.nof_prb * SRSLTE_NRE - 2*36 + (cell.id%3==2?1:0);
} else {
2015-03-18 05:59:29 -07:00
input += cell.nof_prb * SRSLTE_NRE - 2*36 + (cell.id%3==2?1:0);
}
2014-06-17 02:11:41 -07:00
}
/* symbols 2 & 3 */
2015-03-18 05:59:29 -07:00
if (SRSLTE_CP_ISNORM(cell.cp)) {
2014-06-17 07:32:19 -07:00
for (i = 0; i < 2; i++) {
2014-06-17 02:11:41 -07:00
prb_cp(&input, &output, 6);
if (put) {
2015-03-18 05:59:29 -07:00
output += cell.nof_prb * SRSLTE_NRE - 2*36;
} else {
2015-03-18 05:59:29 -07:00
input += cell.nof_prb * SRSLTE_NRE - 2*36;
}
2014-06-17 02:11:41 -07:00
}
} else {
prb_cp(&input, &output, 6);
if (put) {
2015-03-18 05:59:29 -07:00
output += cell.nof_prb * SRSLTE_NRE - 2*36;
} else {
2015-03-18 05:59:29 -07:00
input += cell.nof_prb * SRSLTE_NRE - 2*36;
}
prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
2014-06-17 02:11:41 -07:00
}
if (put) {
return input - ptr;
} else {
return output - ptr;
}
}
/**
* Puts PBCH in slot number 1
*
* Returns the number of symbols written to slot1_data
*
* 36.211 10.3 section 6.6.4
*/
2015-03-18 11:14:24 -07:00
int srslte_pbch_put(cf_t *pbch, cf_t *slot1_data, srslte_cell_t cell) {
return srslte_pbch_cp(pbch, slot1_data, cell, true);
}
/**
* Extracts PBCH from slot number 1
*
* Returns the number of symbols written to pbch
*
* 36.211 10.3 section 6.6.4
*/
2015-03-18 11:14:24 -07:00
int srslte_pbch_get(cf_t *slot1_data, cf_t *pbch, srslte_cell_t cell) {
return srslte_pbch_cp(slot1_data, pbch, cell, false);
}
/** Initializes the PBCH transmitter and receiver.
* At the receiver, the field nof_ports in the cell structure indicates the
* maximum number of BS transmitter ports to look for.
*/
2015-03-18 11:14:24 -07:00
int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
2014-06-17 02:11:41 -07:00
if (q != NULL &&
2015-03-18 05:59:29 -07:00
srslte_cell_isvalid(&cell))
{
ret = SRSLTE_ERROR;
2014-06-17 02:11:41 -07:00
2015-03-18 11:14:24 -07:00
bzero(q, sizeof(srslte_pbch_t));
if (cell.nof_ports == 0) {
q->search_all_ports = true;
cell.nof_ports = SRSLTE_MAX_PORTS;
} else {
q->search_all_ports = false;
}
q->cell = cell;
q->nof_symbols = (SRSLTE_CP_ISNORM(q->cell.cp)) ? PBCH_RE_CP_NORM : PBCH_RE_CP_EXT;
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean;
}
2015-03-18 11:14:24 -07:00
if (srslte_sequence_pbch(&q->seq, q->cell.cp, q->cell.id)) {
goto clean;
}
2014-06-17 02:11:41 -07:00
int poly[3] = { 0x6D, 0x4F, 0x57 };
2015-03-18 08:05:38 -07:00
if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, 40, true)) {
2014-06-17 02:11:41 -07:00
goto clean;
}
2015-03-18 08:05:38 -07:00
if (srslte_crc_init(&q->crc, SRSLTE_LTE_CRC16, 16)) {
2014-06-17 02:11:41 -07:00
goto clean;
}
q->encoder.K = 7;
q->encoder.R = 3;
q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
2015-03-18 11:14:24 -07:00
q->d = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->d) {
2014-06-17 02:11:41 -07:00
goto clean;
}
int i;
for (i = 0; i < q->cell.nof_ports; i++) {
2015-03-18 11:14:24 -07:00
q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) {
goto clean;
}
2015-03-18 11:14:24 -07:00
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->x[i]) {
goto clean;
}
2015-03-18 11:14:24 -07:00
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->symbols[i]) {
goto clean;
}
}
2015-03-18 11:14:24 -07:00
q->llr = srslte_vec_malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->llr) {
goto clean;
}
2015-03-18 11:14:24 -07:00
q->temp = srslte_vec_malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->temp) {
goto clean;
}
2015-03-18 11:14:24 -07:00
q->rm_b = srslte_vec_malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->rm_b) {
goto clean;
}
ret = SRSLTE_SUCCESS;
2014-06-17 02:11:41 -07:00
}
clean:
if (ret == SRSLTE_ERROR) {
2015-03-18 11:14:24 -07:00
srslte_pbch_free(q);
2014-06-17 02:11:41 -07:00
}
return ret;
}
2015-03-18 11:14:24 -07:00
void srslte_pbch_free(srslte_pbch_t *q) {
if (q->d) {
free(q->d);
2014-06-17 02:11:41 -07:00
}
int i;
for (i = 0; i < q->cell.nof_ports; i++) {
2014-06-17 02:11:41 -07:00
if (q->ce[i]) {
free(q->ce[i]);
}
2015-03-18 11:14:24 -07:00
if (q->x[i]) {
free(q->x[i]);
2014-06-17 02:11:41 -07:00
}
2015-03-18 11:14:24 -07:00
if (q->symbols[i]) {
free(q->symbols[i]);
2014-06-17 02:11:41 -07:00
}
}
2015-03-18 11:14:24 -07:00
if (q->llr) {
free(q->llr);
2014-06-17 02:11:41 -07:00
}
if (q->temp) {
free(q->temp);
}
2015-03-18 11:14:24 -07:00
if (q->rm_b) {
free(q->rm_b);
2014-06-17 02:11:41 -07:00
}
2015-03-18 11:14:24 -07:00
srslte_sequence_free(&q->seq);
srslte_modem_table_free(&q->mod);
2015-03-18 08:05:38 -07:00
srslte_viterbi_free(&q->decoder);
2015-03-18 11:14:24 -07:00
bzero(q, sizeof(srslte_pbch_t));
}
/** Unpacks MIB from PBCH message.
* msg buffer must be 24 byte length at least
*/
2015-03-18 11:14:24 -07:00
void srslte_pbch_mib_unpack(uint8_t *msg, srslte_cell_t *cell, uint32_t *sfn) {
int phich_res;
2015-09-14 01:20:12 -07:00
cell->bw_idx = srslte_bit_pack(&msg, 3);
switch (cell->bw_idx) {
case 0:
cell->nof_prb = 6;
break;
case 1:
cell->nof_prb = 15;
break;
default:
cell->nof_prb = (cell->bw_idx - 1) * 25;
break;
}
if (*msg) {
2015-03-18 05:59:29 -07:00
cell->phich_length = SRSLTE_PHICH_EXT;
} else {
2015-03-18 05:59:29 -07:00
cell->phich_length = SRSLTE_PHICH_NORM;
}
msg++;
2015-09-14 01:20:12 -07:00
phich_res = srslte_bit_pack(&msg, 2);
switch (phich_res) {
case 0:
2016-04-04 12:44:07 -07:00
cell->phich_resources = SRSLTE_PHICH_R_1_6;
break;
case 1:
2016-04-04 12:44:07 -07:00
cell->phich_resources = SRSLTE_PHICH_R_1_2;
break;
case 2:
2015-03-18 05:59:29 -07:00
cell->phich_resources = SRSLTE_PHICH_R_1;
break;
case 3:
2015-03-18 05:59:29 -07:00
cell->phich_resources = SRSLTE_PHICH_R_2;
break;
}
if (sfn) {
2015-09-14 01:20:12 -07:00
*sfn = srslte_bit_pack(&msg, 8) << 2;
}
}
/** Unpacks MIB from PBCH message.
* msg buffer must be 24 byte length at least
*/
2015-03-18 11:14:24 -07:00
void srslte_pbch_mib_pack(srslte_cell_t *cell, uint32_t sfn, uint8_t *msg) {
int bw, phich_res = 0;
bzero(msg, 24);
if (cell->nof_prb <= 6) {
bw = 0;
} else if (cell->nof_prb <= 15) {
bw = 1;
} else {
bw = 1 + cell->nof_prb / 25;
}
2015-09-14 01:20:12 -07:00
srslte_bit_unpack(bw, &msg, 3);
2015-03-18 05:59:29 -07:00
*msg = cell->phich_length == SRSLTE_PHICH_EXT;
msg++;
switch (cell->phich_resources) {
2016-04-04 12:44:07 -07:00
case SRSLTE_PHICH_R_1_6:
phich_res = 0;
break;
2016-04-04 12:44:07 -07:00
case SRSLTE_PHICH_R_1_2:
phich_res = 1;
break;
2015-03-18 05:59:29 -07:00
case SRSLTE_PHICH_R_1:
phich_res = 2;
break;
2015-03-18 05:59:29 -07:00
case SRSLTE_PHICH_R_2:
phich_res = 3;
break;
}
2015-09-14 01:20:12 -07:00
srslte_bit_unpack(phich_res, &msg, 2);
srslte_bit_unpack(sfn >> 2, &msg, 8);
}
2015-03-18 11:14:24 -07:00
void srslte_pbch_decode_reset(srslte_pbch_t *q) {
2014-06-17 02:11:41 -07:00
q->frame_idx = 0;
}
2015-03-18 08:05:38 -07:00
void srslte_crc_set_mask(uint8_t *data, int nof_ports) {
2014-06-17 02:11:41 -07:00
int i;
2014-06-17 07:32:19 -07:00
for (i = 0; i < 16; i++) {
data[SRSLTE_BCH_PAYLOAD_LEN + i] = (data[SRSLTE_BCH_PAYLOAD_LEN + i] + srslte_crc_mask[nof_ports - 1][i]) % 2;
2014-06-17 02:11:41 -07:00
}
}
/* Checks CRC after applying the mask for the given number of ports.
*
* The bits buffer size must be at least 40 bytes.
*
* Returns 0 if the data is correct, -1 otherwise
*/
2015-03-18 11:14:24 -07:00
uint32_t srslte_pbch_crc_check(srslte_pbch_t *q, uint8_t *bits, uint32_t nof_ports) {
uint8_t data[SRSLTE_BCH_PAYLOADCRC_LEN];
memcpy(data, bits, SRSLTE_BCH_PAYLOADCRC_LEN * sizeof(uint8_t));
2015-03-18 08:05:38 -07:00
srslte_crc_set_mask(data, nof_ports);
int ret = srslte_crc_checksum(&q->crc, data, SRSLTE_BCH_PAYLOADCRC_LEN);
if (ret == 0) {
uint32_t chkzeros=0;
for (int i=0;i<SRSLTE_BCH_PAYLOAD_LEN;i++) {
chkzeros += data[i];
}
if (chkzeros) {
return 0;
} else {
return SRSLTE_ERROR;
}
} else {
return ret;
}
}
2015-03-18 11:14:24 -07:00
int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
uint32_t nof_bits, uint32_t nof_ports) {
2014-06-17 02:11:41 -07:00
int j;
2014-10-24 03:06:04 -07:00
2015-03-18 11:14:24 -07:00
memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits],
2014-06-17 07:32:19 -07:00
n * nof_bits * sizeof(float));
2014-06-17 02:11:41 -07:00
/* descramble */
2015-03-18 11:14:24 -07:00
srslte_scrambling_f_offset(&q->seq, &q->temp[dst * nof_bits], dst * nof_bits,
2014-06-17 07:32:19 -07:00
n * nof_bits);
2014-06-17 02:11:41 -07:00
2014-06-17 07:32:19 -07:00
for (j = 0; j < dst * nof_bits; j++) {
2015-03-18 08:05:38 -07:00
q->temp[j] = SRSLTE_RX_NULL;
2014-06-17 02:11:41 -07:00
}
2014-06-17 07:32:19 -07:00
for (j = (dst + n) * nof_bits; j < 4 * nof_bits; j++) {
2015-03-18 08:05:38 -07:00
q->temp[j] = SRSLTE_RX_NULL;
2014-06-17 02:11:41 -07:00
}
/* unrate matching */
srslte_rm_conv_rx(q->temp, 4 * nof_bits, q->rm_f, SRSLTE_BCH_ENCODED_LEN);
2014-10-19 03:47:48 -07:00
/* Normalize LLR */
srslte_vec_sc_prod_fff(q->rm_f, 1.0/((float) 2*n), q->rm_f, SRSLTE_BCH_ENCODED_LEN);
2014-06-17 02:11:41 -07:00
/* decode */
srslte_viterbi_decode_f(&q->decoder, q->rm_f, q->data, SRSLTE_BCH_PAYLOADCRC_LEN);
2014-06-17 02:11:41 -07:00
2015-03-18 11:14:24 -07:00
if (!srslte_pbch_crc_check(q, q->data, nof_ports)) {
2014-06-17 02:11:41 -07:00
return 1;
} else {
return SRSLTE_SUCCESS;
2014-06-17 02:11:41 -07:00
}
}
/* Decodes the PBCH channel
*
* The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB
* given the symbols of a subframe (1 ms). Successive calls will use more subframes
* to help the decoding process.
*
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
*/
2015-03-18 11:14:24 -07:00
int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRSLTE_MAX_PORTS], float noise_estimate,
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, int *sfn_offset)
{
uint32_t src, dst, nb;
2014-10-24 03:06:04 -07:00
uint32_t nant;
2014-06-17 02:11:41 -07:00
int i;
int nof_bits;
2015-03-18 05:59:29 -07:00
cf_t *x[SRSLTE_MAX_LAYERS];
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
slot1_symbols != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (ce_slot1[i] == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
2014-06-17 02:11:41 -07:00
/* Set pointers for layermapping & precoding */
nof_bits = 2 * q->nof_symbols;
2014-06-17 02:11:41 -07:00
/* number of layers equals number of ports */
2015-03-18 05:41:50 -07:00
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
2015-03-18 11:14:24 -07:00
x[i] = q->x[i];
}
2015-03-18 05:59:29 -07:00
memset(&x[SRSLTE_MAX_PORTS], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - SRSLTE_MAX_PORTS));
/* extract symbols */
2015-03-18 11:14:24 -07:00
if (q->nof_symbols != srslte_pbch_get(slot1_symbols, q->symbols[0], q->cell)) {
2014-06-17 02:11:41 -07:00
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return SRSLTE_ERROR;
2014-06-17 02:11:41 -07:00
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
2015-03-18 11:14:24 -07:00
if (q->nof_symbols != srslte_pbch_get(ce_slot1[i], q->ce[i], q->cell)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return SRSLTE_ERROR;
}
}
2014-06-17 02:11:41 -07:00
q->frame_idx++;
ret = 0;
2014-06-17 02:11:41 -07:00
/* Try decoding for 1 to cell.nof_ports antennas */
if (q->search_all_ports) {
nant = 1;
} else {
nant = q->cell.nof_ports;
}
do {
2014-10-24 03:06:04 -07:00
if (nant != 3) {
DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
/* in control channels, only diversity is supported */
2014-10-24 03:06:04 -07:00
if (nant == 1) {
/* no need for layer demapping */
2015-10-16 02:05:13 -07:00
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate);
2014-10-24 03:06:04 -07:00
} else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols);
2015-03-18 11:14:24 -07:00
srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant);
2014-10-24 03:06:04 -07:00
}
2014-10-24 03:06:04 -07:00
/* demodulate symbols */
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, &q->llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
2014-12-09 15:29:48 -08:00
2014-10-24 03:06:04 -07:00
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered.
*/
for (nb = 0; nb < q->frame_idx; nb++) {
for (dst = 0; (dst < 4 - nb); dst++) {
for (src = 0; src < q->frame_idx - nb; src++) {
2015-03-18 11:14:24 -07:00
ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant);
2014-10-24 03:06:04 -07:00
if (ret == 1) {
if (sfn_offset) {
*sfn_offset = (int) dst - src + q->frame_idx - 1;
2014-10-24 03:06:04 -07:00
}
if (nof_tx_ports) {
*nof_tx_ports = nant;
}
if (bch_payload) {
memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN);
2014-10-24 03:06:04 -07:00
}
INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + q->frame_idx - 1);
return 1;
2014-10-24 03:06:04 -07:00
}
}
}
2014-06-17 02:11:41 -07:00
}
}
nant++;
} while(nant <= q->cell.nof_ports);
/* If not found, make room for the next packet of radio frame symbols */
if (q->frame_idx == 4) {
2015-03-18 11:14:24 -07:00
memmove(q->llr, &q->llr[nof_bits], nof_bits * 3 * sizeof(float));
q->frame_idx = 3;
}
2014-06-17 02:11:41 -07:00
}
return ret;
}
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], cf_t *slot1_symbols[SRSLTE_MAX_PORTS]) {
2014-06-17 02:11:41 -07:00
int i;
int nof_bits;
2015-03-18 05:59:29 -07:00
cf_t *x[SRSLTE_MAX_LAYERS];
if (q != NULL &&
bch_payload != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (slot1_symbols[i] == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* Set pointers for layermapping & precoding */
nof_bits = 2 * q->nof_symbols;
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
2015-03-18 11:14:24 -07:00
x[i] = q->x[i];
}
2015-03-18 05:59:29 -07:00
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
if (q->frame_idx == 0) {
memcpy(q->data, bch_payload, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN);
/* encode & modulate */
srslte_crc_attach(&q->crc, q->data, SRSLTE_BCH_PAYLOAD_LEN);
2015-03-18 08:05:38 -07:00
srslte_crc_set_mask(q->data, q->cell.nof_ports);
srslte_convcoder_encode(&q->encoder, q->data, q->data_enc, SRSLTE_BCH_PAYLOADCRC_LEN);
srslte_rm_conv_tx(q->data_enc, SRSLTE_BCH_ENCODED_LEN, q->rm_b, 4 * nof_bits);
}
2015-03-18 11:14:24 -07:00
srslte_scrambling_b_offset(&q->seq, &q->rm_b[q->frame_idx * nof_bits],
q->frame_idx * nof_bits, nof_bits);
2015-03-18 11:14:24 -07:00
srslte_mod_modulate(&q->mod, &q->rm_b[q->frame_idx * nof_bits], q->d,
nof_bits);
/* layer mapping & precoding */
if (q->cell.nof_ports > 1) {
2015-03-18 11:14:24 -07:00
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports);
} else {
2015-03-18 11:14:24 -07:00
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
2015-03-18 11:14:24 -07:00
srslte_pbch_put(q->symbols[i], slot1_symbols[i], q->cell);
}
q->frame_idx++;
if (q->frame_idx == 4) {
q->frame_idx = 0;
}
return SRSLTE_SUCCESS;
2014-06-17 02:11:41 -07:00
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
2014-06-17 02:11:41 -07:00
}
}