2020-11-26 01:25:22 -08:00
|
|
|
/**
|
2022-04-29 00:28:44 -07:00
|
|
|
* Copyright 2013-2022 Software Radio Systems Limited
|
2020-11-05 09:55:26 -08:00
|
|
|
*
|
2021-04-22 01:59:40 -07:00
|
|
|
* This file is part of srsRAN.
|
2020-11-05 09:55:26 -08:00
|
|
|
*
|
2021-04-22 01:59:40 -07:00
|
|
|
* srsRAN is free software: you can redistribute it and/or modify
|
2021-03-28 14:12:42 -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.
|
|
|
|
*
|
2021-04-22 01:59:40 -07:00
|
|
|
* srsRAN is distributed in the hope that it will be useful,
|
2021-03-28 14:12:42 -07:00
|
|
|
* 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.
|
2020-11-05 09:55:26 -08:00
|
|
|
*
|
2021-03-28 14:12:42 -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/.
|
2020-11-05 09:55:26 -08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
#include "srsran/phy/phch/sch_nr.h"
|
|
|
|
#include "srsran/config.h"
|
|
|
|
#include "srsran/phy/fec/cbsegm.h"
|
|
|
|
#include "srsran/phy/fec/ldpc/ldpc_common.h"
|
|
|
|
#include "srsran/phy/fec/ldpc/ldpc_rm.h"
|
|
|
|
#include "srsran/phy/phch/ra_nr.h"
|
|
|
|
#include "srsran/phy/utils/bit.h"
|
|
|
|
#include "srsran/phy/utils/debug.h"
|
|
|
|
#include "srsran/phy/utils/vector.h"
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2020-12-22 02:39:59 -08:00
|
|
|
#define SCH_INFO_TX(...) INFO("SCH Tx: " __VA_ARGS__)
|
|
|
|
#define SCH_INFO_RX(...) INFO("SCH Rx: " __VA_ARGS__)
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_basegraph_t srsran_sch_nr_select_basegraph(uint32_t tbs, double R)
|
2020-11-06 10:23:31 -08:00
|
|
|
{
|
|
|
|
// if A ≤ 292 , or if A ≤ 3824 and R ≤ 0.67 , or if R ≤ 0 . 25 , LDPC base graph 2 is used;
|
|
|
|
// otherwise, LDPC base graph 1 is used
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_basegraph_t bg = BG1;
|
2020-12-22 02:39:59 -08:00
|
|
|
if ((tbs <= 292) || (tbs <= 3824 && R <= 0.67) || (R <= 0.25)) {
|
2020-11-06 10:23:31 -08:00
|
|
|
bg = BG2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementation of TS 38.212 V15.9.0 Table 5.4.2.1-1: Value of n_prb_lbrm
|
|
|
|
* @param nof_prb Maximum number of PRBs across all configured DL BWPs and UL BWPs of a carrier for DL-SCH and UL-SCH,
|
|
|
|
* respectively
|
|
|
|
* @return It returns n_prb_lbrm
|
|
|
|
*/
|
|
|
|
uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb)
|
|
|
|
{
|
|
|
|
if (nof_prb < 33) {
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
if (nof_prb <= 66) {
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
if (nof_prb <= 107) {
|
|
|
|
return 107;
|
|
|
|
}
|
|
|
|
if (nof_prb <= 135) {
|
|
|
|
return 135;
|
|
|
|
}
|
|
|
|
if (nof_prb <= 162) {
|
|
|
|
return 162;
|
|
|
|
}
|
|
|
|
if (nof_prb <= 217) {
|
|
|
|
return 217;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 273;
|
|
|
|
}
|
|
|
|
|
2021-05-04 04:15:21 -07:00
|
|
|
static int sch_nr_cbsegm(srsran_basegraph_t bg, uint32_t tbs, srsran_cbsegm_t* cbsegm)
|
|
|
|
{
|
|
|
|
if (bg == BG1) {
|
|
|
|
if (srsran_cbsegm_ldpc_bg1(cbsegm, tbs) != SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d", tbs);
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (srsran_cbsegm_ldpc_bg2(cbsegm, tbs) != SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d", tbs);
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SRSRAN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sch_nr_Nref(uint32_t N_rb, srsran_mcs_table_t mcs_table, uint32_t max_mimo_layers)
|
|
|
|
{
|
|
|
|
uint32_t N_re_lbrm = SRSRAN_MAX_NRE_NR * sch_nr_n_prb_lbrm(N_rb);
|
|
|
|
double TCR_lbrm = 948.0 / 1024.0;
|
|
|
|
uint32_t Qm_lbrm = (mcs_table == srsran_mcs_table_256qam) ? 8 : 6;
|
2021-10-19 06:28:48 -07:00
|
|
|
uint32_t TBS_LRBM = srsran_ra_nr_tbs(N_re_lbrm, 1.0, TCR_lbrm, Qm_lbrm, SRSRAN_MIN(4, max_mimo_layers));
|
2021-05-04 04:15:21 -07:00
|
|
|
double R = 2.0 / 3.0;
|
|
|
|
srsran_basegraph_t bg = srsran_sch_nr_select_basegraph(TBS_LRBM, R);
|
|
|
|
|
|
|
|
// Compute segmentation
|
|
|
|
srsran_cbsegm_t cbsegm = {};
|
|
|
|
int r = sch_nr_cbsegm(bg, TBS_LRBM, &cbsegm);
|
|
|
|
if (r < SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error computing TB segmentation");
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)ceil((double)TBS_LRBM / (double)(cbsegm.C * R));
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_sch_nr_fill_tb_info(const srsran_carrier_nr_t* carrier,
|
|
|
|
const srsran_sch_cfg_t* sch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
|
|
|
srsran_sch_nr_tb_info_t* cfg)
|
2020-11-06 10:23:31 -08:00
|
|
|
{
|
2020-11-10 11:04:12 -08:00
|
|
|
if (!sch_cfg || !tb || !cfg) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// LDPC base graph selection
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_basegraph_t bg = srsran_sch_nr_select_basegraph(tb->tbs, tb->R);
|
2020-11-06 10:23:31 -08:00
|
|
|
|
|
|
|
// Compute code block segmentation
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_cbsegm_t cbsegm = {};
|
2021-05-04 04:15:21 -07:00
|
|
|
if (sch_nr_cbsegm(bg, tb->tbs, &cbsegm) < SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error calculation TB segmentation");
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cbsegm.Z > MAX_LIFTSIZE) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: lifting size Z=%d is out-of-range maximum is %d", cbsegm.Z, MAX_LIFTSIZE);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
cfg->bg = bg;
|
2021-03-19 03:45:56 -07:00
|
|
|
cfg->Qm = srsran_mod_bits_x_symbol(tb->mod);
|
2020-11-06 10:23:31 -08:00
|
|
|
cfg->A = tb->tbs;
|
|
|
|
cfg->L_tb = cbsegm.L_tb;
|
|
|
|
cfg->L_cb = cbsegm.L_cb;
|
|
|
|
cfg->B = cbsegm.tbs + cbsegm.L_tb;
|
|
|
|
cfg->Bp = cfg->B + cbsegm.L_cb * cbsegm.C;
|
|
|
|
cfg->Kp = cfg->Bp / cbsegm.C;
|
|
|
|
cfg->Kr = cbsegm.K1;
|
|
|
|
cfg->F = cfg->Kr - cfg->Kp;
|
|
|
|
cfg->Z = cbsegm.Z;
|
|
|
|
cfg->G = tb->nof_bits;
|
|
|
|
cfg->Nl = tb->N_L;
|
|
|
|
|
|
|
|
// Calculate Nref
|
2021-10-19 06:28:48 -07:00
|
|
|
if (sch_cfg->limited_buffer_rm) {
|
|
|
|
int Nref = sch_nr_Nref(carrier->nof_prb, sch_cfg->mcs_table, 4);
|
|
|
|
if (Nref < SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error computing N_ref");
|
|
|
|
}
|
|
|
|
cfg->Nref = (uint32_t)Nref;
|
|
|
|
} else {
|
|
|
|
cfg->Nref = SRSRAN_LDPC_MAX_LEN_ENCODED_CB;
|
2021-05-04 04:15:21 -07:00
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
|
|
|
|
// Calculate number of code blocks after applying CBGTI... not implemented, activate all CB
|
|
|
|
for (uint32_t r = 0; r < cbsegm.C; r++) {
|
|
|
|
cfg->mask[r] = true;
|
|
|
|
}
|
2021-03-19 03:45:56 -07:00
|
|
|
for (uint32_t r = cbsegm.C; r < SRSRAN_SCH_NR_MAX_NOF_CB_LDPC; r++) {
|
2020-11-06 10:23:31 -08:00
|
|
|
cfg->mask[r] = false;
|
|
|
|
}
|
|
|
|
cfg->C = cbsegm.C;
|
|
|
|
cfg->Cp = cbsegm.C;
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define MOD(NUM, DEN) ((NUM) % (DEN))
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
static inline uint32_t sch_nr_get_E(const srsran_sch_nr_tb_info_t* cfg, uint32_t j)
|
2020-11-06 10:23:31 -08:00
|
|
|
{
|
|
|
|
if (cfg->Nl == 0 || cfg->Qm == 0 || cfg->Cp == 0) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Invalid Nl (%d), Qm (%d) or Cp (%d)", cfg->Nl, cfg->Qm, cfg->Cp);
|
2020-11-06 10:23:31 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j <= (cfg->Cp - MOD(cfg->G / (cfg->Nl * cfg->Qm), cfg->Cp) - 1)) {
|
|
|
|
return cfg->Nl * cfg->Qm * (cfg->G / (cfg->Nl * cfg->Qm * cfg->Cp));
|
|
|
|
}
|
2021-03-19 03:45:56 -07:00
|
|
|
return cfg->Nl * cfg->Qm * SRSRAN_CEIL(cfg->G, cfg->Nl * cfg->Qm * cfg->Cp);
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
static inline int sch_nr_init_common(srsran_sch_nr_t* q)
|
2020-11-05 09:55:26 -08:00
|
|
|
{
|
|
|
|
if (q == NULL) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_crc_init(&q->crc_tb_24, SRSRAN_LTE_CRC24A, 24) < SRSRAN_SUCCESS) {
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_crc_init(&q->crc_cb, SRSRAN_LTE_CRC24B, 24) < SRSRAN_SUCCESS) {
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_crc_init(&q->crc_tb_16, SRSRAN_LTE_CRC16, 16) < SRSRAN_SUCCESS) {
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
if (!q->temp_cb) {
|
2021-03-19 03:45:56 -07:00
|
|
|
q->temp_cb = srsran_vec_u8_malloc(SRSRAN_LDPC_MAX_LEN_CB * 8);
|
2020-11-06 10:23:31 -08:00
|
|
|
if (!q->temp_cb) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_sch_nr_init_tx(srsran_sch_nr_t* q, const srsran_sch_nr_args_t* args)
|
2020-11-06 10:23:31 -08:00
|
|
|
{
|
|
|
|
int ret = sch_nr_init_common(q);
|
2021-03-19 03:45:56 -07:00
|
|
|
if (ret < SRSRAN_SUCCESS) {
|
2020-11-06 10:23:31 -08:00
|
|
|
return ret;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_encoder_type_t encoder_type = SRSRAN_LDPC_ENCODER_C;
|
2021-02-15 07:45:37 -08:00
|
|
|
|
|
|
|
#ifdef LV_HAVE_AVX512
|
|
|
|
if (!args->disable_simd) {
|
2021-03-19 03:45:56 -07:00
|
|
|
encoder_type = SRSRAN_LDPC_ENCODER_AVX512;
|
2021-02-15 07:45:37 -08:00
|
|
|
}
|
|
|
|
#else // LV_HAVE_AVX512
|
2020-11-11 07:13:25 -08:00
|
|
|
#ifdef LV_HAVE_AVX2
|
|
|
|
if (!args->disable_simd) {
|
2021-03-19 03:45:56 -07:00
|
|
|
encoder_type = SRSRAN_LDPC_ENCODER_AVX2;
|
2020-11-11 07:13:25 -08:00
|
|
|
}
|
|
|
|
#endif // LV_HAVE_AVX2
|
2021-02-15 07:45:37 -08:00
|
|
|
#endif // LV_HAVE_AVX612
|
2020-11-05 09:55:26 -08:00
|
|
|
|
|
|
|
// Iterate over all possible lifting sizes
|
2020-11-06 10:23:31 -08:00
|
|
|
for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) {
|
2020-11-05 09:55:26 -08:00
|
|
|
uint8_t ls_index = get_ls_index(ls);
|
|
|
|
|
|
|
|
// Invalid lifting size
|
|
|
|
if (ls_index == VOID_LIFTSIZE) {
|
|
|
|
q->encoder_bg1[ls] = NULL;
|
|
|
|
q->encoder_bg2[ls] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
q->encoder_bg1[ls] = SRSRAN_MEM_ALLOC(srsran_ldpc_encoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
if (!q->encoder_bg1[ls]) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: calloc");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2021-03-19 03:45:56 -07:00
|
|
|
SRSRAN_MEM_ZERO(q->encoder_bg1[ls], srsran_ldpc_encoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising BG1 LDPC encoder for ls=%d", ls);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
q->encoder_bg2[ls] = SRSRAN_MEM_ALLOC(srsran_ldpc_encoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
if (!q->encoder_bg2[ls]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2021-03-19 03:45:56 -07:00
|
|
|
SRSRAN_MEM_ZERO(q->encoder_bg2[ls], srsran_ldpc_encoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising BG2 LDPC encoder for ls=%d", ls);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_ldpc_rm_tx_init(&q->tx_rm) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising Tx LDPC Rate matching");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_sch_nr_init_rx(srsran_sch_nr_t* q, const srsran_sch_nr_args_t* args)
|
2020-11-05 09:55:26 -08:00
|
|
|
{
|
2020-11-06 10:23:31 -08:00
|
|
|
int ret = sch_nr_init_common(q);
|
2021-03-19 03:45:56 -07:00
|
|
|
if (ret < SRSRAN_SUCCESS) {
|
2020-11-06 10:23:31 -08:00
|
|
|
return ret;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_decoder_type_t decoder_type =
|
|
|
|
args->decoder_use_flooded ? SRSRAN_LDPC_DECODER_C_FLOOD : SRSRAN_LDPC_DECODER_C;
|
2021-02-15 07:45:37 -08:00
|
|
|
|
|
|
|
#ifdef LV_HAVE_AVX512
|
|
|
|
if (!args->disable_simd) {
|
2021-03-19 03:45:56 -07:00
|
|
|
decoder_type = args->decoder_use_flooded ? SRSRAN_LDPC_DECODER_C_AVX512_FLOOD : SRSRAN_LDPC_DECODER_C_AVX512;
|
2021-02-15 07:45:37 -08:00
|
|
|
}
|
|
|
|
#else // LV_HAVE_AVX512
|
2020-11-05 09:55:26 -08:00
|
|
|
#ifdef LV_HAVE_AVX2
|
2021-02-15 07:45:37 -08:00
|
|
|
if (!args->disable_simd) {
|
2021-03-19 03:45:56 -07:00
|
|
|
decoder_type = args->decoder_use_flooded ? SRSRAN_LDPC_DECODER_C_AVX2_FLOOD : SRSRAN_LDPC_DECODER_C_AVX2;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2021-02-15 07:45:37 -08:00
|
|
|
#endif // LV_HAVE_AVX2
|
|
|
|
#endif // LV_HAVE_AVX512
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2020-12-22 06:42:34 -08:00
|
|
|
// If the scaling factor is not provided use a default value that allows decoding all possible combinations of nPRB
|
|
|
|
// and MCS indexes for all possible MCS tables
|
|
|
|
float scaling_factor = isnormal(args->decoder_scaling_factor) ? args->decoder_scaling_factor : 0.8f;
|
2020-11-05 09:55:26 -08:00
|
|
|
|
|
|
|
// Iterate over all possible lifting sizes
|
2020-11-06 10:23:31 -08:00
|
|
|
for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) {
|
2020-11-05 09:55:26 -08:00
|
|
|
uint8_t ls_index = get_ls_index(ls);
|
|
|
|
|
|
|
|
// Invalid lifting size
|
|
|
|
if (ls_index == VOID_LIFTSIZE) {
|
|
|
|
q->decoder_bg1[ls] = NULL;
|
|
|
|
q->decoder_bg2[ls] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-04-14 04:47:18 -07:00
|
|
|
// Initialise LDPC configuration arguments
|
|
|
|
srsran_ldpc_decoder_args_t decoder_args = {};
|
|
|
|
decoder_args.type = decoder_type;
|
|
|
|
decoder_args.ls = ls;
|
|
|
|
decoder_args.scaling_fctr = scaling_factor;
|
|
|
|
decoder_args.max_nof_iter = args->max_nof_iter;
|
|
|
|
|
|
|
|
q->decoder_bg1[ls] = SRSRAN_MEM_ALLOC(srsran_ldpc_decoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
if (!q->decoder_bg1[ls]) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: calloc");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2021-04-14 04:47:18 -07:00
|
|
|
SRSRAN_MEM_ZERO(q->decoder_bg1[ls], srsran_ldpc_decoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-04-14 04:47:18 -07:00
|
|
|
decoder_args.bg = BG1;
|
|
|
|
if (srsran_ldpc_decoder_init(q->decoder_bg1[ls], &decoder_args) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising BG1 LDPC decoder for ls=%d", ls);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-04-14 04:47:18 -07:00
|
|
|
q->decoder_bg2[ls] = SRSRAN_MEM_ALLOC(srsran_ldpc_decoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
if (!q->decoder_bg2[ls]) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: calloc");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2021-04-14 04:47:18 -07:00
|
|
|
SRSRAN_MEM_ZERO(q->decoder_bg2[ls], srsran_ldpc_decoder_t, 1);
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-04-14 04:47:18 -07:00
|
|
|
decoder_args.bg = BG2;
|
|
|
|
if (srsran_ldpc_decoder_init(q->decoder_bg2[ls], &decoder_args) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising BG2 LDPC decoder for ls=%d", ls);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
if (srsran_ldpc_rm_rx_init_c(&q->rx_rm) < SRSRAN_SUCCESS) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: initialising Rx LDPC Rate matching");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_sch_nr_set_carrier(srsran_sch_nr_t* q, const srsran_carrier_nr_t* carrier)
|
2020-11-05 09:55:26 -08:00
|
|
|
{
|
2020-11-06 10:23:31 -08:00
|
|
|
if (!q) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
q->carrier = *carrier;
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
void srsran_sch_nr_free(srsran_sch_nr_t* q)
|
2020-11-05 09:55:26 -08:00
|
|
|
{
|
2020-11-06 10:23:31 -08:00
|
|
|
// Protect pointer
|
|
|
|
if (!q) {
|
2020-11-05 09:55:26 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
if (q->temp_cb) {
|
|
|
|
free(q->temp_cb);
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) {
|
|
|
|
if (q->encoder_bg1[ls]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_encoder_free(q->encoder_bg1[ls]);
|
2020-11-06 10:23:31 -08:00
|
|
|
free(q->encoder_bg1[ls]);
|
|
|
|
}
|
|
|
|
if (q->encoder_bg2[ls]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_encoder_free(q->encoder_bg2[ls]);
|
2020-11-06 10:23:31 -08:00
|
|
|
free(q->encoder_bg2[ls]);
|
|
|
|
}
|
|
|
|
if (q->decoder_bg1[ls]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_decoder_free(q->decoder_bg1[ls]);
|
2020-11-06 10:23:31 -08:00
|
|
|
free(q->decoder_bg1[ls]);
|
|
|
|
}
|
|
|
|
if (q->decoder_bg2[ls]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_decoder_free(q->decoder_bg2[ls]);
|
2020-11-06 10:23:31 -08:00
|
|
|
free(q->decoder_bg2[ls]);
|
|
|
|
}
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_rm_tx_free(&q->tx_rm);
|
|
|
|
srsran_ldpc_rm_rx_free_c(&q->rx_rm);
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
static inline int sch_nr_encode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* sch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
2020-12-28 09:28:16 -08:00
|
|
|
const uint8_t* data,
|
|
|
|
uint8_t* e_bits)
|
2020-11-05 09:55:26 -08:00
|
|
|
{
|
|
|
|
// Pointer protection
|
2020-12-28 09:28:16 -08:00
|
|
|
if (!q || !sch_cfg || !tb || !data || !e_bits) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-12-15 08:57:37 -08:00
|
|
|
if (!tb->softbuffer.tx) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: Missing Tx softbuffer");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-12-15 08:57:37 -08:00
|
|
|
}
|
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
const uint8_t* input_ptr = data;
|
|
|
|
uint8_t* output_ptr = e_bits;
|
2020-11-05 09:55:26 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_sch_nr_tb_info_t cfg = {};
|
|
|
|
if (srsran_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSRAN_SUCCESS) {
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-02 10:43:49 -08:00
|
|
|
// Select encoder and CRC
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_encoder_t* encoder = (cfg.bg == BG1) ? q->encoder_bg1[cfg.Z] : q->encoder_bg2[cfg.Z];
|
|
|
|
srsran_crc_t* crc_tb = (cfg.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16;
|
2021-03-02 10:43:49 -08:00
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
// Check encoder
|
2021-03-02 10:43:49 -08:00
|
|
|
if (encoder == NULL) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: encoder for lifting size Z=%d not found (tbs=%d)", cfg.Z, tb->tbs);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
|
|
|
|
// Check CRC for TB
|
2021-03-02 10:43:49 -08:00
|
|
|
if (crc_tb == NULL) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: CRC for TB not found");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Soft-buffer number of code-block protection
|
2020-11-09 23:59:32 -08:00
|
|
|
if (tb->softbuffer.tx->max_cb < cfg.C) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Soft-buffer does not have enough code-blocks (max_cb=%d) for a TBS=%d, C=%d.",
|
2020-11-09 23:59:32 -08:00
|
|
|
tb->softbuffer.tx->max_cb,
|
|
|
|
tb->tbs,
|
|
|
|
cfg.C);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-09 23:59:32 -08:00
|
|
|
}
|
|
|
|
|
2021-03-02 10:43:49 -08:00
|
|
|
if (tb->softbuffer.tx->max_cb_size < (encoder->liftN - 2 * cfg.Z)) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Soft-buffer code-block maximum size insufficient (max_cb_size=%d) for a TBS=%d, requires %d.",
|
2020-11-09 23:59:32 -08:00
|
|
|
tb->softbuffer.tx->max_cb_size,
|
|
|
|
tb->tbs,
|
2021-03-02 10:43:49 -08:00
|
|
|
(encoder->liftN - 2 * cfg.Z));
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
// Calculate TB CRC
|
2021-03-19 03:45:56 -07:00
|
|
|
uint32_t checksum_tb = srsran_crc_checksum_byte(crc_tb, data, tb->tbs);
|
2021-10-26 02:48:29 -07:00
|
|
|
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_DEBUG && !is_handler_registered()) {
|
2020-12-22 02:39:59 -08:00
|
|
|
DEBUG("tb=");
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_vec_fprint_byte(stdout, data, tb->tbs / 8);
|
2020-11-11 03:43:18 -08:00
|
|
|
}
|
2020-11-05 09:55:26 -08:00
|
|
|
|
|
|
|
// For each code block...
|
|
|
|
uint32_t j = 0;
|
2020-11-06 10:23:31 -08:00
|
|
|
for (uint32_t r = 0; r < cfg.C; r++) {
|
|
|
|
// Select rate matching circular buffer
|
2020-11-05 09:55:26 -08:00
|
|
|
uint8_t* rm_buffer = tb->softbuffer.tx->buffer_b[r];
|
2020-11-06 10:23:31 -08:00
|
|
|
if (rm_buffer == NULL) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: soft-buffer provided NULL buffer for cb_idx=%d", r);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
// If data provided, encode and store in RM circular buffer
|
|
|
|
if (data != NULL) {
|
2020-11-09 23:59:32 -08:00
|
|
|
uint32_t cb_len = cfg.Kp - cfg.L_cb;
|
|
|
|
|
2020-11-05 09:55:26 -08:00
|
|
|
// If it is the last segment...
|
2020-11-06 10:23:31 -08:00
|
|
|
if (r == cfg.C - 1) {
|
2020-11-11 03:43:18 -08:00
|
|
|
cb_len -= cfg.L_tb;
|
|
|
|
|
2020-11-05 09:55:26 -08:00
|
|
|
// Copy payload without TB CRC
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_bit_unpack_vector(input_ptr, q->temp_cb, (int)cb_len);
|
2020-11-05 09:55:26 -08:00
|
|
|
|
|
|
|
// Append TB CRC
|
2020-11-11 03:43:18 -08:00
|
|
|
uint8_t* ptr = &q->temp_cb[cb_len];
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_bit_unpack(checksum_tb, &ptr, cfg.L_tb);
|
2021-02-10 04:46:25 -08:00
|
|
|
SCH_INFO_TX("CB %d: appending TB CRC=%06x", r, checksum_tb);
|
2020-11-05 09:55:26 -08:00
|
|
|
} else {
|
|
|
|
// Copy payload
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_bit_unpack_vector(input_ptr, q->temp_cb, (int)cb_len);
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2020-11-11 03:43:18 -08:00
|
|
|
|
2021-10-26 02:48:29 -07:00
|
|
|
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_DEBUG && !is_handler_registered()) {
|
2020-12-22 02:39:59 -08:00
|
|
|
DEBUG("cb%d=", r);
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_vec_fprint_byte(stdout, input_ptr, cb_len / 8);
|
2020-11-11 03:43:18 -08:00
|
|
|
}
|
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
input_ptr += cb_len / 8;
|
2020-11-05 09:55:26 -08:00
|
|
|
|
|
|
|
// Attach code block CRC if required
|
2020-11-06 10:23:31 -08:00
|
|
|
if (cfg.L_cb) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_crc_attach(&q->crc_cb, q->temp_cb, (int)(cfg.Kp - cfg.L_cb));
|
|
|
|
SCH_INFO_TX("CB %d: CRC=%06x", r, (uint32_t)srsran_crc_checksum_get(&q->crc_cb));
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Insert filler bits
|
2020-11-06 10:23:31 -08:00
|
|
|
for (uint32_t i = cfg.Kp; i < cfg.Kr; i++) {
|
|
|
|
q->temp_cb[i] = FILLER_BIT;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Encode code block
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_encoder_encode(encoder, q->temp_cb, rm_buffer, cfg.Kr);
|
2020-12-15 08:57:37 -08:00
|
|
|
|
2021-10-26 02:48:29 -07:00
|
|
|
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_DEBUG && !is_handler_registered()) {
|
2020-12-22 02:39:59 -08:00
|
|
|
DEBUG("encoded=");
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_vec_fprint_b(stdout, rm_buffer, encoder->liftN - 2 * encoder->ls);
|
2020-12-15 08:57:37 -08:00
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Skip block
|
|
|
|
if (!cfg.mask[r]) {
|
|
|
|
continue;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Select rate matching output sequence number of bits
|
2020-11-06 10:23:31 -08:00
|
|
|
uint32_t E = sch_nr_get_E(&cfg, j);
|
|
|
|
j++;
|
|
|
|
|
|
|
|
// LDPC Rate matching
|
2021-02-10 04:46:25 -08:00
|
|
|
SCH_INFO_TX("RM CB %d: E=%d; F=%d; BG=%d; Z=%d; RV=%d; Qm=%d; Nref=%d;",
|
2020-12-22 02:39:59 -08:00
|
|
|
r,
|
|
|
|
E,
|
|
|
|
cfg.F,
|
|
|
|
cfg.bg == BG1 ? 1 : 2,
|
|
|
|
cfg.Z,
|
|
|
|
tb->rv,
|
|
|
|
cfg.Qm,
|
|
|
|
cfg.Nref);
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_rm_tx(&q->tx_rm, rm_buffer, output_ptr, E, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref);
|
2020-11-06 10:23:31 -08:00
|
|
|
output_ptr += E;
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
static int sch_nr_decode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* sch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
|
|
|
int8_t* e_bits,
|
|
|
|
srsran_sch_tb_res_nr_t* res)
|
2020-11-06 10:23:31 -08:00
|
|
|
{
|
|
|
|
// Pointer protection
|
2021-04-14 11:23:17 -07:00
|
|
|
if (!q || !sch_cfg || !tb || !e_bits || !res) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-08-03 04:00:01 -07:00
|
|
|
// Protect softbuffer access
|
2021-07-23 00:18:29 -07:00
|
|
|
if (!tb->softbuffer.rx) {
|
|
|
|
ERROR("Missing softbuffer!");
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-08-03 04:00:01 -07:00
|
|
|
// Protect PDU access
|
|
|
|
if (!res->payload) {
|
|
|
|
ERROR("Missing payload pointer!");
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
int8_t* input_ptr = e_bits;
|
|
|
|
uint32_t nof_iter_sum = 0;
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_sch_nr_tb_info_t cfg = {};
|
|
|
|
if (srsran_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSRAN_SUCCESS) {
|
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-03-02 10:43:49 -08:00
|
|
|
// Select encoder and CRC
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_ldpc_decoder_t* decoder = (cfg.bg == BG1) ? q->decoder_bg1[cfg.Z] : q->decoder_bg2[cfg.Z];
|
|
|
|
srsran_crc_t* crc_tb = (cfg.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16;
|
2021-03-02 10:43:49 -08:00
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
// Check decoder
|
2021-03-02 10:43:49 -08:00
|
|
|
if (decoder == NULL) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: decoder for lifting size Z=%d not found", cfg.Z);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check CRC for TB
|
2021-03-02 10:43:49 -08:00
|
|
|
if (crc_tb == NULL) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: CRC for TB not found");
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Soft-buffer number of code-block protection
|
2021-03-02 10:43:49 -08:00
|
|
|
if (tb->softbuffer.rx->max_cb < cfg.Cp || tb->softbuffer.rx->max_cb_size < (decoder->liftN - 2 * cfg.Z)) {
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Counter of code blocks that have matched CRC
|
|
|
|
uint32_t cb_ok = 0;
|
2022-01-17 02:25:03 -08:00
|
|
|
res->crc = false;
|
2020-11-06 10:23:31 -08:00
|
|
|
|
|
|
|
// For each code block...
|
|
|
|
uint32_t j = 0;
|
|
|
|
for (uint32_t r = 0; r < cfg.C; r++) {
|
|
|
|
bool decoded = tb->softbuffer.rx->cb_crc[r];
|
|
|
|
int8_t* rm_buffer = (int8_t*)tb->softbuffer.tx->buffer_b[r];
|
|
|
|
if (!rm_buffer) {
|
2021-02-10 04:46:25 -08:00
|
|
|
ERROR("Error: soft-buffer provided NULL buffer for cb_idx=%d", r);
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_ERROR;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
// Skip CB if mask indicates no transmission of the CB
|
|
|
|
if (!cfg.mask[r]) {
|
|
|
|
if (decoded) {
|
|
|
|
cb_ok++;
|
|
|
|
}
|
2021-02-10 04:46:25 -08:00
|
|
|
SCH_INFO_RX("RM CB %d: Disabled, CRC %s ... Skipping", r, decoded ? "OK" : "KO");
|
2020-11-06 10:23:31 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
// Select rate matching output sequence number of bits
|
2020-11-06 10:23:31 -08:00
|
|
|
uint32_t E = sch_nr_get_E(&cfg, j);
|
|
|
|
j++;
|
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
// Skip CB if it has a matched CRC
|
|
|
|
if (decoded) {
|
2021-02-10 04:46:25 -08:00
|
|
|
SCH_INFO_RX("RM CB %d: CRC OK ... Skipping", r);
|
2020-11-09 23:59:32 -08:00
|
|
|
cb_ok++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-06 10:23:31 -08:00
|
|
|
// LDPC Rate matching
|
2021-02-10 04:46:25 -08:00
|
|
|
SCH_INFO_RX("RM CB %d: E=%d; F=%d; BG=%d; Z=%d; RV=%d; Qm=%d; Nref=%d;",
|
2020-12-22 02:39:59 -08:00
|
|
|
r,
|
|
|
|
E,
|
|
|
|
cfg.F,
|
|
|
|
cfg.bg == BG1 ? 1 : 2,
|
|
|
|
cfg.Z,
|
|
|
|
tb->rv,
|
|
|
|
cfg.Qm,
|
|
|
|
cfg.Nref);
|
2021-03-25 11:44:27 -07:00
|
|
|
int n_llr =
|
|
|
|
srsran_ldpc_rm_rx_c(&q->rx_rm, input_ptr, rm_buffer, E, cfg.F, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref);
|
|
|
|
if (n_llr < SRSRAN_SUCCESS) {
|
|
|
|
ERROR("Error in LDPC rate mateching");
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
// Select CB or TB early stop CRC
|
|
|
|
srsran_crc_t* crc = (cfg.L_tb == 16) ? &q->crc_tb_16 : &q->crc_tb_24;
|
2020-11-06 10:23:31 -08:00
|
|
|
if (cfg.L_cb) {
|
2021-04-14 11:23:17 -07:00
|
|
|
crc = &q->crc_cb;
|
2020-11-06 10:23:31 -08:00
|
|
|
}
|
|
|
|
|
2021-04-23 07:48:35 -07:00
|
|
|
// Decode. if CRC=KO, then ret=0
|
|
|
|
int ret = srsran_ldpc_decoder_decode_crc_c(decoder, rm_buffer, q->temp_cb, n_llr, crc);
|
|
|
|
if (ret < SRSRAN_SUCCESS) {
|
2021-04-14 11:23:17 -07:00
|
|
|
ERROR("Error decoding CB");
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-04-23 07:48:35 -07:00
|
|
|
// Compute number of iterations
|
|
|
|
uint32_t n_iter_cb = (ret == 0) ? decoder->max_nof_iter : (uint32_t)ret;
|
|
|
|
nof_iter_sum += n_iter_cb;
|
|
|
|
|
|
|
|
// Check if CB is all zeros
|
2021-07-07 03:47:30 -07:00
|
|
|
uint32_t cb_len = cfg.Kp - cfg.L_cb;
|
2021-04-23 07:48:35 -07:00
|
|
|
|
2021-07-07 03:47:30 -07:00
|
|
|
tb->softbuffer.rx->cb_crc[r] = (ret != 0);
|
|
|
|
SCH_INFO_RX("CB %d/%d iter=%d CRC=%s", r, cfg.C, n_iter_cb, tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO");
|
2021-04-23 07:48:35 -07:00
|
|
|
|
|
|
|
// CB Debug trace
|
2021-10-26 02:48:29 -07:00
|
|
|
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_DEBUG && !is_handler_registered()) {
|
2021-04-23 07:48:35 -07:00
|
|
|
DEBUG("CB %d/%d:", r, cfg.C);
|
|
|
|
srsran_vec_fprint_hex(stdout, q->temp_cb, cb_len);
|
|
|
|
}
|
2021-04-14 11:23:17 -07:00
|
|
|
|
2020-11-09 23:59:32 -08:00
|
|
|
// Pack and count CRC OK only if CRC is match
|
|
|
|
if (tb->softbuffer.rx->cb_crc[r]) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran_bit_pack_vector(q->temp_cb, tb->softbuffer.rx->data[r], cb_len);
|
2020-11-09 23:59:32 -08:00
|
|
|
cb_ok++;
|
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
|
|
|
|
input_ptr += E;
|
|
|
|
}
|
2021-04-23 07:48:35 -07:00
|
|
|
// Set average number of iterations
|
|
|
|
res->avg_iter = (float)nof_iter_sum / (float)cfg.C;
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-04-23 07:48:35 -07:00
|
|
|
// Set average number of iterations
|
|
|
|
if (cfg.C > 0) {
|
|
|
|
res->avg_iter = (float)nof_iter_sum / (float)cfg.C;
|
|
|
|
} else {
|
|
|
|
res->avg_iter = NAN;
|
|
|
|
}
|
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
// Not all CB are decoded, skip TB union and CRC check
|
|
|
|
if (cb_ok != cfg.C) {
|
|
|
|
return SRSRAN_SUCCESS;
|
|
|
|
}
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
uint32_t checksum2 = 0;
|
|
|
|
uint8_t* output_ptr = res->payload;
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
for (uint32_t r = 0; r < cfg.C; r++) {
|
|
|
|
uint32_t cb_len = cfg.Kp - cfg.L_cb;
|
2020-11-06 10:23:31 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
// Subtract TB CRC from the last code block
|
|
|
|
if (r == cfg.C - 1) {
|
|
|
|
cb_len -= cfg.L_tb;
|
|
|
|
}
|
2020-11-11 03:43:18 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
// Append CB
|
|
|
|
srsran_vec_u8_copy(output_ptr, tb->softbuffer.rx->data[r], cb_len / 8);
|
|
|
|
output_ptr += cb_len / 8;
|
|
|
|
|
|
|
|
// Compute TB CRC for last block
|
|
|
|
if (cfg.C > 1 && r == cfg.C - 1) {
|
|
|
|
uint8_t tb_crc_unpacked[24] = {};
|
|
|
|
uint8_t* tb_crc_unpacked_ptr = tb_crc_unpacked;
|
|
|
|
srsran_bit_unpack_vector(&tb->softbuffer.rx->data[r][cb_len / 8], tb_crc_unpacked, cfg.L_tb);
|
|
|
|
checksum2 = srsran_bit_pack(&tb_crc_unpacked_ptr, cfg.L_tb);
|
2021-02-03 02:06:01 -08:00
|
|
|
}
|
2021-04-14 11:23:17 -07:00
|
|
|
}
|
2021-02-03 02:06:01 -08:00
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
// Calculate TB CRC from packed data
|
|
|
|
if (cfg.C == 1) {
|
|
|
|
SCH_INFO_RX("TB: TBS=%d; CRC=%s", tb->tbs, tb->softbuffer.rx->cb_crc[0] ? "OK" : "KO");
|
2021-04-26 02:44:19 -07:00
|
|
|
res->crc = true;
|
2020-11-06 10:23:31 -08:00
|
|
|
} else {
|
2021-04-14 11:23:17 -07:00
|
|
|
// More than one
|
|
|
|
uint32_t checksum1 = srsran_crc_checksum_byte(crc_tb, res->payload, tb->tbs);
|
2021-04-23 07:48:35 -07:00
|
|
|
res->crc = (checksum1 == checksum2);
|
2021-04-14 11:23:17 -07:00
|
|
|
SCH_INFO_RX("TB: TBS=%d; CRC={%06x, %06x}", tb->tbs, checksum1, checksum2);
|
|
|
|
}
|
|
|
|
|
2021-10-26 02:48:29 -07:00
|
|
|
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_DEBUG && !is_handler_registered()) {
|
2021-04-14 11:23:17 -07:00
|
|
|
DEBUG("Decode: ");
|
|
|
|
srsran_vec_fprint_byte(stdout, res->payload, tb->tbs / 8);
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
return SRSRAN_SUCCESS;
|
2020-11-05 09:55:26 -08:00
|
|
|
}
|
2020-11-20 03:12:29 -08:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_dlsch_nr_encode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* pdsch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
2020-12-28 09:28:16 -08:00
|
|
|
const uint8_t* data,
|
|
|
|
uint8_t* e_bits)
|
|
|
|
{
|
|
|
|
return sch_nr_encode(q, pdsch_cfg, tb, data, e_bits);
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_dlsch_nr_decode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* sch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
2020-12-28 09:28:16 -08:00
|
|
|
int8_t* e_bits,
|
2021-04-14 11:23:17 -07:00
|
|
|
srsran_sch_tb_res_nr_t* res)
|
2020-12-28 09:28:16 -08:00
|
|
|
{
|
2021-04-14 11:23:17 -07:00
|
|
|
return sch_nr_decode(q, sch_cfg, tb, e_bits, res);
|
2020-12-28 09:28:16 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_ulsch_nr_encode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* pdsch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
2020-12-28 09:28:16 -08:00
|
|
|
const uint8_t* data,
|
|
|
|
uint8_t* e_bits)
|
|
|
|
{
|
|
|
|
return sch_nr_encode(q, pdsch_cfg, tb, data, e_bits);
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
int srsran_ulsch_nr_decode(srsran_sch_nr_t* q,
|
|
|
|
const srsran_sch_cfg_t* sch_cfg,
|
|
|
|
const srsran_sch_tb_t* tb,
|
2020-12-28 09:28:16 -08:00
|
|
|
int8_t* e_bits,
|
2021-04-14 11:23:17 -07:00
|
|
|
srsran_sch_tb_res_nr_t* res)
|
2020-12-28 09:28:16 -08:00
|
|
|
{
|
2021-04-14 11:23:17 -07:00
|
|
|
return sch_nr_decode(q, sch_cfg, tb, e_bits, res);
|
2020-12-28 09:28:16 -08:00
|
|
|
}
|
|
|
|
|
2021-04-14 11:23:17 -07:00
|
|
|
int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, const srsran_sch_tb_res_nr_t* res, char* str, uint32_t str_len)
|
2020-11-20 03:12:29 -08:00
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (tb->enabled) {
|
2021-04-14 11:23:17 -07:00
|
|
|
len = srsran_print_check(str,
|
|
|
|
str_len,
|
|
|
|
len,
|
2021-04-16 02:58:43 -07:00
|
|
|
"CW%d: mod=%s tbs=%d R=%.3f rv=%d ",
|
2021-04-14 11:23:17 -07:00
|
|
|
tb->cw_idx,
|
|
|
|
srsran_mod_string(tb->mod),
|
|
|
|
tb->tbs / 8,
|
2021-07-07 05:13:29 -07:00
|
|
|
tb->R_prime,
|
2021-04-16 02:58:43 -07:00
|
|
|
tb->rv);
|
2021-04-14 11:23:17 -07:00
|
|
|
|
|
|
|
if (res != NULL) {
|
|
|
|
len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter);
|
|
|
|
}
|
2020-11-20 03:12:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
2021-04-23 07:48:35 -07:00
|
|
|
}
|