diff --git a/lib/include/srslte/phy/phch/ra_nr.h b/lib/include/srslte/phy/phch/ra_nr.h index 4df787fe8..37a244d2e 100644 --- a/lib/include/srslte/phy/phch/ra_nr.h +++ b/lib/include/srslte/phy/phch/ra_nr.h @@ -47,7 +47,7 @@ typedef struct SRSLTE_API { int tbs; ///< Payload size, TS 38.212 refers to it as A double R; ///< Target LDPC rate int rv; - uint32_t nof_bits; + uint32_t nof_bits; ///< Number of available bits to send, known as G uint32_t cw_idx; bool enabled; diff --git a/lib/include/srslte/phy/phch/sch_nr.h b/lib/include/srslte/phy/phch/sch_nr.h index 1c865293e..13c724fe2 100644 --- a/lib/include/srslte/phy/phch/sch_nr.h +++ b/lib/include/srslte/phy/phch/sch_nr.h @@ -39,11 +39,15 @@ #include "srslte/phy/phch/pdsch_cfg_nr.h" #include "srslte/phy/phch/ra_nr.h" +#define SRSLTE_SCH_NR_MAX_NOF_CB_LDPC \ + (SRSLTE_MAX_PRB_NR * SRSLTE_NRE * 8 * SRSLTE_NSYMB_PER_SLOT_NR * (SRSLTE_LDPC_BG2_MAX_LEN_CB + 1) / \ + SRSLTE_LDPC_BG2_MAX_LEN_CB) + typedef struct SRSLTE_API { srslte_carrier_nr_t carrier; /// Temporal data buffers - uint8_t* cb_in; + uint8_t* temp_cb; /// CRC generators srslte_crc_t crc_tb_24; @@ -51,12 +55,17 @@ typedef struct SRSLTE_API { srslte_crc_t crc_cb; /// LDPC encoders - srslte_ldpc_encoder_t* encoder_bg1[MAX_LIFTSIZE]; - srslte_ldpc_encoder_t* encoder_bg2[MAX_LIFTSIZE]; + srslte_ldpc_encoder_t* encoder_bg1[MAX_LIFTSIZE + 1]; + srslte_ldpc_encoder_t* encoder_bg2[MAX_LIFTSIZE + 1]; + + /// LDPC decoders + srslte_ldpc_decoder_t* decoder_bg1[MAX_LIFTSIZE + 1]; + srslte_ldpc_decoder_t* decoder_bg2[MAX_LIFTSIZE + 1]; /// LDPC Rate matcher - srslte_ldpc_rm_t rm; -} srslte_sch_nr_encoder_t; + srslte_ldpc_rm_t tx_rm; + srslte_ldpc_rm_t rx_rm; +} srslte_sch_nr_t; typedef struct SRSLTE_API { bool disable_simd; @@ -64,50 +73,77 @@ typedef struct SRSLTE_API { float scaling_factor; } srslte_sch_nr_decoder_cfg_t; -typedef struct SRSLTE_API { - /// CRC generators - srslte_crc_t crc_tb_24; - srslte_crc_t crc_tb_16; - srslte_crc_t crc_cb; - - /// LDPC decoders - srslte_ldpc_decoder_t* decoder_bg1[MAX_LIFTSIZE]; - srslte_ldpc_decoder_t* decoder_bg2[MAX_LIFTSIZE]; - - /// LDPC Tx/Rx Rate matcher - srslte_ldpc_rm_t rm; -} srslte_sch_nr_decoder_t; +/** + * @brief Common SCH configuration + */ +typedef struct { + srslte_basegraph_t bg; ///< @brief Base graph + uint32_t Qm; ///< @brief Modulation order + uint32_t G; ///< Number of available bits + uint32_t A; ///< @brief Payload size, TBS + uint32_t L_tb; ///< @brief the number of the transport block parity bits (16 or 24 bits) + uint32_t L_cb; ///< @brief the number of the code block parity bits (0 or 24 bits) + uint32_t B; ///< @brief the number of bits in the transport block including TB CRC + uint32_t Bp; ///< @brief the number of bits in the transport block including CB and TB CRCs + uint32_t Kp; ///< @brief Number of payload bits of the code block including CB CRC + uint32_t Kr; ///< @brief Number of payload bits of the code block including CB CRC and filler bits + uint32_t F; ///< @brief Number of filler bits + uint32_t Nref; ///< @brief N_ref parameter described in TS 38.212 V15.9.0 5.4.2.1 + uint32_t Z; ///< @brief LDPC lifting size + uint32_t Nl; ///< @brief Number of transmission layers that the transport block is mapped onto + bool mask[SRSLTE_SCH_NR_MAX_NOF_CB_LDPC]; ///< Indicates what codeblocks shall be encoded/decoded + uint32_t C; ///< Number of codeblocks + uint32_t Cp; ///< Number of codeblocks that are actually transmitted + srslte_crc_t* crc_tb; ///< Selected CRC for transport block + srslte_ldpc_encoder_t* encoder; ///< @brief Points to the selected encoder (if valid) + srslte_ldpc_decoder_t* decoder; ///< @brief Points to the selected decoder (if valid) +} srslte_sch_nr_common_cfg_t; /** - * @brief Initialises shared channel encoder - * @param q + * @brief Base graph selection from a provided transport block size and target rate + * + * @remark Defined for DL-SCH in TS 38.212 V15.9.0 section 7.2.2 LDPC base graph selection + * @remark Defined for UL-SCH in TS 38.212 V15.9.0 section 6.2.2 LDPC base graph selection + * + * @param tbs the payload size as described in Clause 7.2.1 for DL-SCH and 6.2.1 for UL-SCH. + * @param R Target rate + * @return it returns the selected base graph + */ +SRSLTE_API srslte_basegraph_t srslte_sch_nr_select_basegraph(uint32_t tbs, double R); + +/** + * @brief Calculates all the parameters required for performing TS 38.212 V15.9.0 5.4 General procedures for LDPC + * @param pdsch_cfg Provides higher layers configuration + * @param tb Provides transport block configuration + * @param cfg SCH object * @return */ -SRSLTE_API int srslte_sch_nr_encoder_init(srslte_sch_nr_encoder_t* q); +SRSLTE_API int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q, + const srslte_pdsch_cfg_nr_t* pdsch_cfg, + const srslte_ra_tb_nr_t* tb, + srslte_sch_nr_common_cfg_t* cfg); -SRSLTE_API int srslte_sch_nr_encoder_set_carrier(srslte_sch_nr_encoder_t* q, const srslte_carrier_nr_t* carrier); +SRSLTE_API int srslte_sch_nr_init_tx(srslte_sch_nr_t* q); -SRSLTE_API int srslte_dlsch_nr_encode(srslte_sch_nr_encoder_t* q, +SRSLTE_API int srslte_sch_nr_init_rx(srslte_sch_nr_t* q, const srslte_sch_nr_decoder_cfg_t* cfg); + +SRSLTE_API int srslte_sch_nr_set_carrier(srslte_sch_nr_t* q, const srslte_carrier_nr_t* carrier); + +SRSLTE_API void srslte_sch_nr_free(srslte_sch_nr_t* q); + +SRSLTE_API int srslte_dlsch_nr_encode(srslte_sch_nr_t* q, const srslte_pdsch_cfg_nr_t* cfg, const srslte_ra_tb_nr_t* tb, const uint8_t* data, uint8_t* e_bits); -SRSLTE_API void srslte_sch_nr_encoder_free(srslte_sch_nr_encoder_t* q); +SRSLTE_API int srslte_sch_nr_decoder_set_carrier(srslte_sch_nr_t* q, const srslte_carrier_nr_t* carrier); -/** - * @brief Initialises shared channel decoder - * @param q - * @return - */ -SRSLTE_API int srslte_sch_nr_init_decoder(srslte_sch_nr_decoder_t* q, const srslte_sch_nr_decoder_cfg_t* cfg); - -SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_decoder_t* q, - const srslte_pdsch_cfg_nr_t* cfg, - const srslte_pdsch_grant_nr_t* grant, - int8_t* e_bits, - uint8_t* data); - -SRSLTE_API void srslte_sch_nr_decoder_free(srslte_sch_nr_decoder_t* q); +SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_ra_tb_nr_t* tb, + int8_t* e_bits, + uint8_t* data, + bool* crc_ok); #endif // SRSLTE_SCH_NR_H \ No newline at end of file diff --git a/lib/src/phy/fec/cbsegm.c b/lib/src/phy/fec/cbsegm.c index 76e66f1e6..0ed03393e 100644 --- a/lib/src/phy/fec/cbsegm.c +++ b/lib/src/phy/fec/cbsegm.c @@ -165,7 +165,7 @@ static int cbsegm_ldpc_select_ls(uint32_t Kp, uint32_t K_b, uint32_t* Z_c, uint8 } // Iterate from the minimum required lift size to the maximum value - for (uint16_t Z = Kp / K_b; Z < MAX_LIFTSIZE; Z++) { + for (uint16_t Z = Kp / K_b; Z <= MAX_LIFTSIZE; Z++) { // Get index for a selected lifting size uint8_t i = get_ls_index(Z); diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index d4445e7c0..aebce1e5a 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -375,5 +375,8 @@ int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg, tb->mod = m; tb->nof_bits = N_re * Qm * grant->nof_layers; + // Calculate number of layers accordingly + tb->N_L = grant->nof_layers; + return SRSLTE_SUCCESS; } \ No newline at end of file diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index a0f0dd041..f63a17a64 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -27,236 +27,17 @@ #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" -#include -#include -#include -int srslte_sch_nr_encoder_init(srslte_sch_nr_encoder_t* q) +srslte_basegraph_t srslte_sch_nr_select_basegraph(uint32_t tbs, double R) { - if (q == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; + // 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 + srslte_basegraph_t bg = BG1; + if ((tbs <= 292) || (tbs <= 292 && R <= 0.67) || (R <= 0.25)) { + bg = BG2; } - if (srslte_crc_init(&q->crc_tb_24, SRSLTE_LTE_CRC24A, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_cb, SRSLTE_LTE_CRC24B, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_tb_16, SRSLTE_LTE_CRC16, 16) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - q->cb_in = srslte_vec_u8_malloc(SRSLTE_LDPC_MAX_LEN_CB); - if (!q->cb_in) { - return SRSLTE_ERROR; - } - -#ifdef LV_HAVE_AVX2 - srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_AVX2; -#else // LV_HAVE_AVX2 - srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_C; -#endif // LV_HAVE_AVX2 - - // Iterate over all possible lifting sizes - for (uint16_t ls = 0; ls < MAX_LIFTSIZE; ls++) { - 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; - } - - q->encoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); - if (!q->encoder_bg1[ls]) { - ERROR("Error: calloc\n"); - return SRSLTE_ERROR; - } - - if (srslte_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG1 LDPC encoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - - q->encoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); - if (!q->encoder_bg2[ls]) { - return SRSLTE_ERROR; - } - - if (srslte_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG2 LDPC encoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - } - - return SRSLTE_SUCCESS; -} - -int srslte_sch_nr_encoder_set_carrier(srslte_sch_nr_encoder_t* q, const srslte_carrier_nr_t* carrier) -{ - if (!q) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - q->carrier = *carrier; - - return SRSLTE_SUCCESS; -} - -int srslte_sch_nr_decoder_init(srslte_sch_nr_decoder_t* q, const srslte_sch_nr_decoder_cfg_t* decoder_cfg) -{ - if (q == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (srslte_crc_init(&q->crc_tb_24, SRSLTE_LTE_CRC24A, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_cb, SRSLTE_LTE_CRC24B, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_tb_16, SRSLTE_LTE_CRC16, 16) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - srslte_ldpc_decoder_type_t decoder_type = SRSLTE_LDPC_DECODER_C; - if (decoder_cfg->use_flooded) { -#ifdef LV_HAVE_AVX2 - if (decoder_cfg->disable_simd) { - decoder_type = SRSLTE_LDPC_DECODER_C_FLOOD; - } else { - decoder_type = SRSLTE_LDPC_DECODER_C_AVX2_FLOOD; - } -#else // LV_HAVE_AVX2 - decoder_type = SRSLTE_LDPC_DECODER_C_FLOOD; -#endif // LV_HAVE_AVX2 - } else { -#ifdef LV_HAVE_AVX2 - if (!decoder_cfg->disable_simd) { - decoder_type = SRSLTE_LDPC_DECODER_C_AVX2; - } -#endif // LV_HAVE_AVX2 - } - - float scaling_factor = isnormal(decoder_cfg->scaling_factor) ? decoder_cfg->scaling_factor : 0.75f; - - // Iterate over all possible lifting sizes - for (uint16_t ls = 0; ls < MAX_LIFTSIZE; ls++) { - 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; - } - - q->decoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_decoder_t)); - if (!q->decoder_bg1[ls]) { - ERROR("Error: calloc\n"); - return SRSLTE_ERROR; - } - - if (srslte_ldpc_decoder_init(q->decoder_bg1[ls], decoder_type, BG1, ls, scaling_factor) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG1 LDPC decoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - - q->decoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_decoder_t)); - if (!q->decoder_bg2[ls]) { - ERROR("Error: calloc\n"); - return SRSLTE_ERROR; - } - - if (srslte_ldpc_decoder_init(q->decoder_bg2[ls], decoder_type, BG2, ls, scaling_factor) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG2 LDPC decoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - } - - return SRSLTE_SUCCESS; -} - -int srslte_(srslte_sch_nr_encoder_t* q) -{ - if (q == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (srslte_crc_init(&q->crc_tb_24, SRSLTE_LTE_CRC24A, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_cb, SRSLTE_LTE_CRC24B, 24) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - if (srslte_crc_init(&q->crc_tb_16, SRSLTE_LTE_CRC16, 16) < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - - q->cb_in = srslte_vec_u8_malloc(SRSLTE_LDPC_MAX_LEN_CB); - if (!q->cb_in) { - return SRSLTE_ERROR; - } - -#ifdef LV_HAVE_AVX2 - srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_AVX2; -#else // LV_HAVE_AVX2 - srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_C; -#endif // LV_HAVE_AVX2 - - // Iterate over all possible lifting sizes - for (uint16_t ls = 0; ls < MAX_LIFTSIZE; ls++) { - 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; - } - - q->encoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); - if (!q->encoder_bg1[ls]) { - ERROR("Error: calloc\n"); - return SRSLTE_ERROR; - } - - if (srslte_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG1 LDPC encoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - - q->encoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); - if (!q->encoder_bg2[ls]) { - return SRSLTE_ERROR; - } - - if (srslte_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSLTE_SUCCESS) { - ERROR("Error: initialising BG2 LDPC encoder for ls=%d\n", ls); - return SRSLTE_ERROR; - } - } - - return SRSLTE_SUCCESS; -} - -void srslte_sch_nr_free(srslte_sch_nr_encoder_t* q) -{ - if (q == NULL) { - return; - } - - if (q->cb_in) { - free(q->cb_in); - } + return bg; } /** @@ -289,33 +70,22 @@ uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb) return 273; } -#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN)) -#define MOD(NUM, DEN) ((NUM) % (DEN)) - -int srslte_dlsch_nr_encode(srslte_sch_nr_encoder_t* q, - const srslte_pdsch_cfg_nr_t* cfg, - const srslte_ra_tb_nr_t* tb, - const uint8_t* data, - uint8_t* e_bits) +int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q, + const srslte_pdsch_cfg_nr_t* pdsch_cfg, + const srslte_ra_tb_nr_t* tb, + srslte_sch_nr_common_cfg_t* cfg) { - // Pointer protection - if (!q || !cfg || !tb || !data || !e_bits) { + + if (!pdsch_cfg || !tb || !cfg) { return SRSLTE_ERROR_INVALID_INPUTS; } - uint8_t* output_ptr = e_bits; - - // TS 38.212 V15.9.0 section 7.2.2 LDPC base graph selection - // 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, - srslte_basegraph_t bg = BG1; - if ((tb->tbs <= 292) || (tb->tbs <= 292 && tb->R <= 0.67) || (tb->R <= 0.25)) { - bg = BG2; - } + // LDPC base graph selection + srslte_basegraph_t bg = srslte_sch_nr_select_basegraph(tb->tbs, tb->R); // Compute code block segmentation srslte_cbsegm_t cbsegm = {}; - if (bg == BG1) { + if (cfg->bg == BG1) { if (srslte_cbsegm_ldpc_bg1(&cbsegm, tb->tbs) != SRSLTE_SUCCESS) { ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d\n", tb->tbs); return SRSLTE_ERROR; @@ -327,105 +97,478 @@ int srslte_dlsch_nr_encode(srslte_sch_nr_encoder_t* q, } } - // Select encoder if (cbsegm.Z > MAX_LIFTSIZE) { - ERROR("Error: lifting size Z=%d is out-of-range\n", cbsegm.Z); - return SRSLTE_ERROR; - } - srslte_ldpc_encoder_t* encoder = (bg == BG1) ? q->encoder_bg1[cbsegm.Z] : q->encoder_bg2[cbsegm.Z]; - if (encoder == NULL) { - ERROR("Error: encoder for lifting size Z=%d not found\n", cbsegm.Z); + ERROR("Error: lifting size Z=%d is out-of-range maximum is %d\n", cbsegm.Z, MAX_LIFTSIZE); return SRSLTE_ERROR; } - // Soft-buffer number of code-block protection - if (tb->softbuffer.tx->max_cb < cbsegm.K1 || tb->softbuffer.tx->max_cb < cbsegm.C) { - return SRSLTE_ERROR; - } - - // Compute derived RM parameters - uint32_t Qm = srslte_mod_bits_x_symbol(tb->mod); + cfg->bg = bg; + cfg->Qm = srslte_mod_bits_x_symbol(tb->mod); + 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 uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(q->carrier.nof_prb); double R_lbrm = 948.0 / 1024.0; - uint32_t Qm_lbrm = (cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6; - uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, R_lbrm, Qm_lbrm, cfg->serving_cell_cfg.max_mimo_layers); - uint32_t Nref = ceil(TBS_LRBM / (cbsegm.C * 2.0 / 3.0)); - uint32_t N_L = tb->N_L; + uint32_t Qm_lbrm = (pdsch_cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6; + uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, R_lbrm, Qm_lbrm, pdsch_cfg->serving_cell_cfg.max_mimo_layers); + cfg->Nref = ceil(TBS_LRBM / (cbsegm.C * 2.0 / 3.0)); - // Calculate number of code blocks after applying CBGTI - uint32_t Cp = cbsegm.C; // ... obviously, not implemented - - // Select CRC - srslte_crc_t* crc_tb = &q->crc_tb_16; - if (cbsegm.L_tb == 24) { - crc_tb = &q->crc_tb_24; + // 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; } - uint32_t checksum_tb = srslte_crc_checksum_byte(crc_tb, data, tb->tbs); + for (uint32_t r = cbsegm.C; r < SRSLTE_SCH_NR_MAX_NOF_CB_LDPC; r++) { + cfg->mask[r] = false; + } + cfg->C = cbsegm.C; + cfg->Cp = cbsegm.C; - // Total number of bits, including CRCs - uint32_t Bp = cbsegm.tbs + cbsegm.L_tb + cbsegm.L_cb * cbsegm.C; + // Select encoder + cfg->encoder = (bg == BG1) ? q->encoder_bg1[cfg->Z] : q->encoder_bg2[cfg->Z]; - // Number of bits per code block - uint32_t Kp = Bp / cbsegm.C; + // Select decoder + cfg->decoder = (bg == BG1) ? q->decoder_bg1[cfg->Z] : q->decoder_bg2[cfg->Z]; + + // Select CRC for TB + cfg->crc_tb = (cbsegm.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16; + + return SRSLTE_SUCCESS; +} + +#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN)) +#define MOD(NUM, DEN) ((NUM) % (DEN)) + +static inline uint32_t sch_nr_get_E(const srslte_sch_nr_common_cfg_t* cfg, uint32_t j) +{ + if (cfg->Nl == 0 || cfg->Qm == 0 || cfg->Cp == 0) { + ERROR("Invalid Nl (%d), Qm (%d) or Cp (%d)\n", cfg->Nl, cfg->Qm, cfg->Cp); + 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)); + } + return cfg->Nl * cfg->Qm * CEIL(cfg->G, cfg->Nl * cfg->Qm * cfg->Cp); +} + +static inline int sch_nr_init_common(srslte_sch_nr_t* q) +{ + if (q == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (srslte_crc_init(&q->crc_tb_24, SRSLTE_LTE_CRC24A, 24) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (srslte_crc_init(&q->crc_cb, SRSLTE_LTE_CRC24B, 24) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (srslte_crc_init(&q->crc_tb_16, SRSLTE_LTE_CRC16, 16) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (!q->temp_cb) { + q->temp_cb = srslte_vec_u8_malloc(SRSLTE_LDPC_MAX_LEN_CB); + if (!q->temp_cb) { + return SRSLTE_ERROR; + } + } + + return SRSLTE_SUCCESS; +} + +int srslte_sch_nr_init_tx(srslte_sch_nr_t* q) +{ + int ret = sch_nr_init_common(q); + if (ret < SRSLTE_SUCCESS) { + return ret; + } + +#ifdef LV_HAVE_AVX2 + srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_AVX2; +#else // LV_HAVE_AVX2 + srslte_ldpc_encoder_type_t encoder_type = SRSLTE_LDPC_ENCODER_C; +#endif // LV_HAVE_AVX2 + + // Iterate over all possible lifting sizes + for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) { + 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; + } + + q->encoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); + if (!q->encoder_bg1[ls]) { + ERROR("Error: calloc\n"); + return SRSLTE_ERROR; + } + + if (srslte_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSLTE_SUCCESS) { + ERROR("Error: initialising BG1 LDPC encoder for ls=%d\n", ls); + return SRSLTE_ERROR; + } + + q->encoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); + if (!q->encoder_bg2[ls]) { + return SRSLTE_ERROR; + } + + if (srslte_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSLTE_SUCCESS) { + ERROR("Error: initialising BG2 LDPC encoder for ls=%d\n", ls); + return SRSLTE_ERROR; + } + } + + if (srslte_ldpc_rm_tx_init(&q->tx_rm) < SRSLTE_SUCCESS) { + ERROR("Error: initialising Tx LDPC Rate matching\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_sch_nr_init_rx(srslte_sch_nr_t* q, const srslte_sch_nr_decoder_cfg_t* decoder_cfg) +{ + int ret = sch_nr_init_common(q); + if (ret < SRSLTE_SUCCESS) { + return ret; + } + + srslte_ldpc_decoder_type_t decoder_type = SRSLTE_LDPC_DECODER_C; + if (decoder_cfg->use_flooded) { +#ifdef LV_HAVE_AVX2 + if (decoder_cfg->disable_simd) { + decoder_type = SRSLTE_LDPC_DECODER_C_FLOOD; + } else { + decoder_type = SRSLTE_LDPC_DECODER_C_AVX2_FLOOD; + } +#else // LV_HAVE_AVX2 + decoder_type = SRSLTE_LDPC_DECODER_C_FLOOD; +#endif // LV_HAVE_AVX2 + } else { +#ifdef LV_HAVE_AVX2 + if (!decoder_cfg->disable_simd) { + decoder_type = SRSLTE_LDPC_DECODER_C_AVX2; + } +#endif // LV_HAVE_AVX2 + } + + float scaling_factor = isnormal(decoder_cfg->scaling_factor) ? decoder_cfg->scaling_factor : 0.75f; + + // Iterate over all possible lifting sizes + for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) { + 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; + } + + q->decoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_decoder_t)); + if (!q->decoder_bg1[ls]) { + ERROR("Error: calloc\n"); + return SRSLTE_ERROR; + } + + if (srslte_ldpc_decoder_init(q->decoder_bg1[ls], decoder_type, BG1, ls, scaling_factor) < SRSLTE_SUCCESS) { + ERROR("Error: initialising BG1 LDPC decoder for ls=%d\n", ls); + return SRSLTE_ERROR; + } + + q->decoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_decoder_t)); + if (!q->decoder_bg2[ls]) { + ERROR("Error: calloc\n"); + return SRSLTE_ERROR; + } + + if (srslte_ldpc_decoder_init(q->decoder_bg2[ls], decoder_type, BG2, ls, scaling_factor) < SRSLTE_SUCCESS) { + ERROR("Error: initialising BG2 LDPC decoder for ls=%d\n", ls); + return SRSLTE_ERROR; + } + } + + if (srslte_ldpc_rm_rx_init_c(&q->rx_rm) < SRSLTE_SUCCESS) { + ERROR("Error: initialising Rx LDPC Rate matching\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_sch_nr_set_carrier(srslte_sch_nr_t* q, const srslte_carrier_nr_t* carrier) +{ + if (!q) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + q->carrier = *carrier; + + return SRSLTE_SUCCESS; +} + +void srslte_sch_nr_free(srslte_sch_nr_t* q) +{ + // Protect pointer + if (!q) { + return; + } + + if (q->temp_cb) { + free(q->temp_cb); + } + + for (uint16_t ls = 0; ls <= MAX_LIFTSIZE; ls++) { + if (q->encoder_bg1[ls]) { + srslte_ldpc_encoder_free(q->encoder_bg1[ls]); + free(q->encoder_bg1[ls]); + } + if (q->encoder_bg2[ls]) { + srslte_ldpc_encoder_free(q->encoder_bg2[ls]); + free(q->encoder_bg2[ls]); + } + if (q->decoder_bg1[ls]) { + srslte_ldpc_decoder_free(q->decoder_bg1[ls]); + free(q->decoder_bg1[ls]); + } + if (q->decoder_bg2[ls]) { + srslte_ldpc_decoder_free(q->decoder_bg2[ls]); + free(q->decoder_bg2[ls]); + } + } + + srslte_ldpc_rm_tx_free(&q->tx_rm); + srslte_ldpc_rm_rx_free_c(&q->rx_rm); +} + +int srslte_dlsch_nr_encode(srslte_sch_nr_t* q, + const srslte_pdsch_cfg_nr_t* pdsch_cfg, + const srslte_ra_tb_nr_t* tb, + const uint8_t* data, + uint8_t* e_bits) +{ + // Pointer protection + if (!q || !pdsch_cfg || !tb || !data || !e_bits) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + uint8_t* output_ptr = e_bits; + + srslte_sch_nr_common_cfg_t cfg = {}; + if (srslte_dlsch_nr_fill_cfg(q, pdsch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check encoder + if (cfg.encoder == NULL) { + ERROR("Error: encoder for lifting size Z=%d not found\n", cfg.Z); + return SRSLTE_ERROR; + } + + // Check CRC for TB + if (cfg.crc_tb == NULL) { + ERROR("Error: CRC for TB not found\n"); + return SRSLTE_ERROR; + } + + // Soft-buffer number of code-block protection + if (tb->softbuffer.tx->max_cb < cfg.Cp || tb->softbuffer.tx->max_cb_size < (cfg.encoder->liftN - 2 * cfg.Z)) { + return SRSLTE_ERROR; + } + + // Calculate TB CRC + uint32_t checksum_tb = srslte_crc_checksum_byte(cfg.crc_tb, data, tb->tbs); // For each code block... uint32_t j = 0; - for (uint32_t r = 0; r < cbsegm.C; r++) { + for (uint32_t r = 0; r < cfg.C; r++) { + // Select rate matching circular buffer uint8_t* rm_buffer = tb->softbuffer.tx->buffer_b[r]; - if (!rm_buffer) { + if (rm_buffer == NULL) { ERROR("Error: soft-buffer provided NULL buffer for cb_idx=%d\n", r); return SRSLTE_ERROR; } - // If data provided, encode and store - if (data) { + // If data provided, encode and store in RM circular buffer + if (data != NULL) { // If it is the last segment... - if (r == cbsegm.C - 1) { + if (r == cfg.C - 1) { // Copy payload without TB CRC - srslte_bit_unpack_vector(data, q->cb_in, (int)(Kp - cbsegm.L_cb - cbsegm.L_tb)); + srslte_bit_unpack_vector(data, q->temp_cb, (int)(cfg.Kp - cfg.L_cb - cfg.L_tb)); // Append TB CRC - uint8_t* ptr = &q->cb_in[Kp - cbsegm.L_cb - cbsegm.L_tb]; - srslte_bit_unpack(checksum_tb, &ptr, cbsegm.L_cb); + uint8_t* ptr = &q->temp_cb[cfg.Kp - cfg.L_cb - cfg.L_tb]; + srslte_bit_unpack(checksum_tb, &ptr, cfg.L_tb); } else { // Copy payload - srslte_bit_unpack_vector(data, q->cb_in, (int)(Kp - cbsegm.L_cb)); + srslte_bit_unpack_vector(data, q->temp_cb, (int)(cfg.Kp - cfg.L_cb)); } // Attach code block CRC if required - if (cbsegm.L_cb) { - srslte_crc_attach(&q->crc_cb, q->cb_in, Kp); + if (cfg.L_cb) { + srslte_crc_attach(&q->crc_cb, q->temp_cb, (int)(cfg.Kp - cfg.L_cb)); } // Insert filler bits - for (uint32_t i = Kp; i < cbsegm.K1; i++) { - q->cb_in[i] = FILLER_BIT; + for (uint32_t i = cfg.Kp; i < cfg.Kr; i++) { + q->temp_cb[i] = FILLER_BIT; } // Encode code block - srslte_ldpc_encoder_encode(encoder, q->cb_in, rm_buffer, cbsegm.K1); + srslte_ldpc_encoder_encode(cfg.encoder, q->temp_cb, rm_buffer, cfg.Kr); + } + + // Skip block + if (!cfg.mask[r]) { + continue; } // Select rate matching output sequence number of bits - uint32_t E = 0; - if (false) { - // if the r -th coded block is not scheduled for transmission as indicated by CBGTI - // ... currently not implemented - } else { - if (r <= (Cp - MOD(tb->nof_bits / (tb->N_L * Qm), Cp) - 1)) { - E = N_L * Qm * (tb->nof_bits / (tb->N_L * Qm * Cp)); - } else { - E = N_L * Qm * CEIL(tb->nof_bits, tb->N_L * Qm * Cp); - } - j++; - } + uint32_t E = sch_nr_get_E(&cfg, j); + j++; // LDPC Rate matching - srslte_ldpc_rm_tx(&q->rm, rm_buffer, output_ptr, E, bg, cbsegm.Z, tb->rv, tb->mod, Nref); + srslte_ldpc_rm_tx(&q->tx_rm, rm_buffer, output_ptr, E, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref); output_ptr += E; } return SRSLTE_SUCCESS; } + +int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, + const srslte_pdsch_cfg_nr_t* pdsch_cfg, + const srslte_ra_tb_nr_t* tb, + int8_t* e_bits, + uint8_t* data, + bool* crc_ok) +{ + // Pointer protection + if (!q || !pdsch_cfg || !tb || !data || !e_bits || !crc_ok) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + int8_t* input_ptr = e_bits; + uint8_t* output_ptr = data; + + srslte_sch_nr_common_cfg_t cfg = {}; + if (srslte_dlsch_nr_fill_cfg(q, pdsch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check decoder + if (cfg.decoder == NULL) { + ERROR("Error: decoder for lifting size Z=%d not found\n", cfg.Z); + return SRSLTE_ERROR; + } + + // Check CRC for TB + if (cfg.crc_tb == NULL) { + ERROR("Error: CRC for TB not found\n"); + return SRSLTE_ERROR; + } + + // Soft-buffer number of code-block protection + if (tb->softbuffer.rx->max_cb < cfg.Cp || tb->softbuffer.rx->max_cb_size < (cfg.decoder->liftN - 2 * cfg.Z)) { + return SRSLTE_ERROR; + } + + // Counter of code blocks that have matched CRC + uint32_t cb_ok = 0; + + // 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) { + ERROR("Error: soft-buffer provided NULL buffer for cb_idx=%d\n", r); + return SRSLTE_ERROR; + } + + // Select rate matching output sequence number of bits + if (decoded) { + cb_ok++; + continue; + } + + uint32_t E = sch_nr_get_E(&cfg, j); + j++; + + // LDPC Rate matching + srslte_ldpc_rm_rx_c(&q->rx_rm, input_ptr, rm_buffer, E, cfg.F, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref); + + // Decode + srslte_ldpc_decoder_decode_c(cfg.decoder, rm_buffer, q->temp_cb); + + // Compute CB CRC + uint32_t cb_len = cfg.Kp - cfg.L_cb; + if (cfg.L_cb) { + uint8_t* ptr = q->temp_cb; + uint32_t checksum1 = srslte_crc_checksum(&q->crc_cb, q->temp_cb, (int)cb_len); + uint32_t checksum2 = srslte_bit_pack(&ptr, cfg.L_cb); + tb->softbuffer.rx->cb_crc[r] = (checksum1 == checksum2); + + // Pack only if CRC is match + if (tb->softbuffer.rx->cb_crc[r]) { + srslte_bit_pack_vector(q->temp_cb, tb->softbuffer.rx->data[r], cb_len); + } + } else { + srslte_bit_pack_vector(q->temp_cb, tb->softbuffer.rx->data[r], cb_len); + tb->softbuffer.rx->cb_crc[r] = true; + } + + // Count if CB CRC OK + cb_ok += tb->softbuffer.rx->cb_crc[r]; + + input_ptr += E; + } + + // All CB are decoded + if (cb_ok == cfg.C) { + uint32_t checksum2 = 0; + + for (uint32_t r = 0; r < cfg.C; r++) { + uint32_t cb_len = cfg.Kp - cfg.L_cb; + + // Subtract TB CRC from the last codde block + if (r == cfg.C - 1) { + cb_len -= cfg.L_tb; + } + + srslte_vec_u8_copy(output_ptr, tb->softbuffer.rx->data[r], cb_len / 8); + output_ptr += cb_len / 8; + + if (r == cfg.C - 1) { + uint8_t tb_crc_unpacked[24] = {}; + uint8_t* tb_crc_unpacked_ptr = tb_crc_unpacked; + srslte_bit_unpack_vector(&tb->softbuffer.rx->data[r][cb_len / 8], tb_crc_unpacked, cfg.L_tb); + checksum2 = srslte_bit_pack(&tb_crc_unpacked_ptr, cfg.L_tb); + } + } + + // Calculate TB CRC from packed data + uint32_t checksum1 = srslte_crc_checksum_byte(cfg.crc_tb, data, tb->tbs); + *crc_ok = (checksum1 == checksum2); + } else { + *crc_ok = false; + } + + return SRSLTE_SUCCESS; +} diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 005d99133..dff195f78 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -617,3 +617,10 @@ if(RF_FOUND) add_executable(prach_test_usrp prach_test_usrp.c) target_link_libraries(prach_test_usrp srslte_rf srslte_phy pthread) endif(RF_FOUND) + +######################################################################## +# NR +######################################################################## + +add_executable(dlsch_nr_test dlsch_nr_test.c) +target_link_libraries(dlsch_nr_test srslte_phy) \ No newline at end of file