mirror of https://github.com/PentHertz/srsLTE.git
Implemented NR DL SCH decoder and unit test
This commit is contained in:
parent
3464dd3c0d
commit
2aa7e43771
|
@ -47,7 +47,7 @@ typedef struct SRSLTE_API {
|
||||||
int tbs; ///< Payload size, TS 38.212 refers to it as A
|
int tbs; ///< Payload size, TS 38.212 refers to it as A
|
||||||
double R; ///< Target LDPC rate
|
double R; ///< Target LDPC rate
|
||||||
int rv;
|
int rv;
|
||||||
uint32_t nof_bits;
|
uint32_t nof_bits; ///< Number of available bits to send, known as G
|
||||||
uint32_t cw_idx;
|
uint32_t cw_idx;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,15 @@
|
||||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||||
#include "srslte/phy/phch/ra_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 {
|
typedef struct SRSLTE_API {
|
||||||
srslte_carrier_nr_t carrier;
|
srslte_carrier_nr_t carrier;
|
||||||
|
|
||||||
/// Temporal data buffers
|
/// Temporal data buffers
|
||||||
uint8_t* cb_in;
|
uint8_t* temp_cb;
|
||||||
|
|
||||||
/// CRC generators
|
/// CRC generators
|
||||||
srslte_crc_t crc_tb_24;
|
srslte_crc_t crc_tb_24;
|
||||||
|
@ -51,12 +55,17 @@ typedef struct SRSLTE_API {
|
||||||
srslte_crc_t crc_cb;
|
srslte_crc_t crc_cb;
|
||||||
|
|
||||||
/// LDPC encoders
|
/// LDPC encoders
|
||||||
srslte_ldpc_encoder_t* encoder_bg1[MAX_LIFTSIZE];
|
srslte_ldpc_encoder_t* encoder_bg1[MAX_LIFTSIZE + 1];
|
||||||
srslte_ldpc_encoder_t* encoder_bg2[MAX_LIFTSIZE];
|
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
|
/// LDPC Rate matcher
|
||||||
srslte_ldpc_rm_t rm;
|
srslte_ldpc_rm_t tx_rm;
|
||||||
} srslte_sch_nr_encoder_t;
|
srslte_ldpc_rm_t rx_rm;
|
||||||
|
} srslte_sch_nr_t;
|
||||||
|
|
||||||
typedef struct SRSLTE_API {
|
typedef struct SRSLTE_API {
|
||||||
bool disable_simd;
|
bool disable_simd;
|
||||||
|
@ -64,50 +73,77 @@ typedef struct SRSLTE_API {
|
||||||
float scaling_factor;
|
float scaling_factor;
|
||||||
} srslte_sch_nr_decoder_cfg_t;
|
} srslte_sch_nr_decoder_cfg_t;
|
||||||
|
|
||||||
typedef struct SRSLTE_API {
|
/**
|
||||||
/// CRC generators
|
* @brief Common SCH configuration
|
||||||
srslte_crc_t crc_tb_24;
|
*/
|
||||||
srslte_crc_t crc_tb_16;
|
typedef struct {
|
||||||
srslte_crc_t crc_cb;
|
srslte_basegraph_t bg; ///< @brief Base graph
|
||||||
|
uint32_t Qm; ///< @brief Modulation order
|
||||||
/// LDPC decoders
|
uint32_t G; ///< Number of available bits
|
||||||
srslte_ldpc_decoder_t* decoder_bg1[MAX_LIFTSIZE];
|
uint32_t A; ///< @brief Payload size, TBS
|
||||||
srslte_ldpc_decoder_t* decoder_bg2[MAX_LIFTSIZE];
|
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)
|
||||||
/// LDPC Tx/Rx Rate matcher
|
uint32_t B; ///< @brief the number of bits in the transport block including TB CRC
|
||||||
srslte_ldpc_rm_t rm;
|
uint32_t Bp; ///< @brief the number of bits in the transport block including CB and TB CRCs
|
||||||
} srslte_sch_nr_decoder_t;
|
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
|
* @brief Base graph selection from a provided transport block size and target rate
|
||||||
* @param q
|
*
|
||||||
|
* @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
|
* @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_pdsch_cfg_nr_t* cfg,
|
||||||
const srslte_ra_tb_nr_t* tb,
|
const srslte_ra_tb_nr_t* tb,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint8_t* e_bits);
|
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);
|
||||||
|
|
||||||
/**
|
SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_t* q,
|
||||||
* @brief Initialises shared channel decoder
|
const srslte_pdsch_cfg_nr_t* cfg,
|
||||||
* @param q
|
const srslte_ra_tb_nr_t* tb,
|
||||||
* @return
|
int8_t* e_bits,
|
||||||
*/
|
uint8_t* data,
|
||||||
SRSLTE_API int srslte_sch_nr_init_decoder(srslte_sch_nr_decoder_t* q, const srslte_sch_nr_decoder_cfg_t* cfg);
|
bool* crc_ok);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
#endif // SRSLTE_SCH_NR_H
|
#endif // SRSLTE_SCH_NR_H
|
|
@ -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
|
// 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
|
// Get index for a selected lifting size
|
||||||
uint8_t i = get_ls_index(Z);
|
uint8_t i = get_ls_index(Z);
|
||||||
|
|
||||||
|
|
|
@ -375,5 +375,8 @@ int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||||
tb->mod = m;
|
tb->mod = m;
|
||||||
tb->nof_bits = N_re * Qm * grant->nof_layers;
|
tb->nof_bits = N_re * Qm * grant->nof_layers;
|
||||||
|
|
||||||
|
// Calculate number of layers accordingly
|
||||||
|
tb->N_L = grant->nof_layers;
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
|
@ -27,236 +27,17 @@
|
||||||
#include "srslte/phy/utils/bit.h"
|
#include "srslte/phy/utils/bit.h"
|
||||||
#include "srslte/phy/utils/debug.h"
|
#include "srslte/phy/utils/debug.h"
|
||||||
#include "srslte/phy/utils/vector.h"
|
#include "srslte/phy/utils/vector.h"
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <strings.h>
|
|
||||||
|
|
||||||
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) {
|
// if A ≤ 292 , or if A ≤ 3824 and R ≤ 0.67 , or if R ≤ 0 . 25 , LDPC base graph 2 is used;
|
||||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
// 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 bg;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -289,33 +70,22 @@ uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb)
|
||||||
return 273;
|
return 273;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
|
int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
||||||
#define MOD(NUM, DEN) ((NUM) % (DEN))
|
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||||
|
const srslte_ra_tb_nr_t* tb,
|
||||||
int srslte_dlsch_nr_encode(srslte_sch_nr_encoder_t* q,
|
srslte_sch_nr_common_cfg_t* cfg)
|
||||||
const srslte_pdsch_cfg_nr_t* cfg,
|
|
||||||
const srslte_ra_tb_nr_t* tb,
|
|
||||||
const uint8_t* data,
|
|
||||||
uint8_t* e_bits)
|
|
||||||
{
|
{
|
||||||
// Pointer protection
|
|
||||||
if (!q || !cfg || !tb || !data || !e_bits) {
|
if (!pdsch_cfg || !tb || !cfg) {
|
||||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* output_ptr = e_bits;
|
// LDPC base graph selection
|
||||||
|
srslte_basegraph_t bg = srslte_sch_nr_select_basegraph(tb->tbs, tb->R);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute code block segmentation
|
// Compute code block segmentation
|
||||||
srslte_cbsegm_t cbsegm = {};
|
srslte_cbsegm_t cbsegm = {};
|
||||||
if (bg == BG1) {
|
if (cfg->bg == BG1) {
|
||||||
if (srslte_cbsegm_ldpc_bg1(&cbsegm, tb->tbs) != SRSLTE_SUCCESS) {
|
if (srslte_cbsegm_ldpc_bg1(&cbsegm, tb->tbs) != SRSLTE_SUCCESS) {
|
||||||
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d\n", tb->tbs);
|
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d\n", tb->tbs);
|
||||||
return SRSLTE_ERROR;
|
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) {
|
if (cbsegm.Z > MAX_LIFTSIZE) {
|
||||||
ERROR("Error: lifting size Z=%d is out-of-range\n", cbsegm.Z);
|
ERROR("Error: lifting size Z=%d is out-of-range maximum is %d\n", cbsegm.Z, MAX_LIFTSIZE);
|
||||||
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);
|
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Soft-buffer number of code-block protection
|
cfg->bg = bg;
|
||||||
if (tb->softbuffer.tx->max_cb < cbsegm.K1 || tb->softbuffer.tx->max_cb < cbsegm.C) {
|
cfg->Qm = srslte_mod_bits_x_symbol(tb->mod);
|
||||||
return SRSLTE_ERROR;
|
cfg->A = tb->tbs;
|
||||||
}
|
cfg->L_tb = cbsegm.L_tb;
|
||||||
|
cfg->L_cb = cbsegm.L_cb;
|
||||||
// Compute derived RM parameters
|
cfg->B = cbsegm.tbs + cbsegm.L_tb;
|
||||||
uint32_t Qm = srslte_mod_bits_x_symbol(tb->mod);
|
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
|
// Calculate Nref
|
||||||
uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(q->carrier.nof_prb);
|
uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(q->carrier.nof_prb);
|
||||||
double R_lbrm = 948.0 / 1024.0;
|
double R_lbrm = 948.0 / 1024.0;
|
||||||
uint32_t Qm_lbrm = (cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6;
|
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, cfg->serving_cell_cfg.max_mimo_layers);
|
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);
|
||||||
uint32_t Nref = ceil(TBS_LRBM / (cbsegm.C * 2.0 / 3.0));
|
cfg->Nref = ceil(TBS_LRBM / (cbsegm.C * 2.0 / 3.0));
|
||||||
uint32_t N_L = tb->N_L;
|
|
||||||
|
|
||||||
// Calculate number of code blocks after applying CBGTI
|
// Calculate number of code blocks after applying CBGTI... not implemented, activate all CB
|
||||||
uint32_t Cp = cbsegm.C; // ... obviously, not implemented
|
for (uint32_t r = 0; r < cbsegm.C; r++) {
|
||||||
|
cfg->mask[r] = true;
|
||||||
// Select CRC
|
|
||||||
srslte_crc_t* crc_tb = &q->crc_tb_16;
|
|
||||||
if (cbsegm.L_tb == 24) {
|
|
||||||
crc_tb = &q->crc_tb_24;
|
|
||||||
}
|
}
|
||||||
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
|
// Select encoder
|
||||||
uint32_t Bp = cbsegm.tbs + cbsegm.L_tb + cbsegm.L_cb * cbsegm.C;
|
cfg->encoder = (bg == BG1) ? q->encoder_bg1[cfg->Z] : q->encoder_bg2[cfg->Z];
|
||||||
|
|
||||||
// Number of bits per code block
|
// Select decoder
|
||||||
uint32_t Kp = Bp / cbsegm.C;
|
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...
|
// For each code block...
|
||||||
uint32_t j = 0;
|
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];
|
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);
|
ERROR("Error: soft-buffer provided NULL buffer for cb_idx=%d\n", r);
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If data provided, encode and store
|
// If data provided, encode and store in RM circular buffer
|
||||||
if (data) {
|
if (data != NULL) {
|
||||||
// If it is the last segment...
|
// If it is the last segment...
|
||||||
if (r == cbsegm.C - 1) {
|
if (r == cfg.C - 1) {
|
||||||
// Copy payload without TB CRC
|
// 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
|
// Append TB CRC
|
||||||
uint8_t* ptr = &q->cb_in[Kp - cbsegm.L_cb - cbsegm.L_tb];
|
uint8_t* ptr = &q->temp_cb[cfg.Kp - cfg.L_cb - cfg.L_tb];
|
||||||
srslte_bit_unpack(checksum_tb, &ptr, cbsegm.L_cb);
|
srslte_bit_unpack(checksum_tb, &ptr, cfg.L_tb);
|
||||||
} else {
|
} else {
|
||||||
// Copy payload
|
// 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
|
// Attach code block CRC if required
|
||||||
if (cbsegm.L_cb) {
|
if (cfg.L_cb) {
|
||||||
srslte_crc_attach(&q->crc_cb, q->cb_in, Kp);
|
srslte_crc_attach(&q->crc_cb, q->temp_cb, (int)(cfg.Kp - cfg.L_cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert filler bits
|
// Insert filler bits
|
||||||
for (uint32_t i = Kp; i < cbsegm.K1; i++) {
|
for (uint32_t i = cfg.Kp; i < cfg.Kr; i++) {
|
||||||
q->cb_in[i] = FILLER_BIT;
|
q->temp_cb[i] = FILLER_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode code block
|
// 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
|
// Select rate matching output sequence number of bits
|
||||||
uint32_t E = 0;
|
uint32_t E = sch_nr_get_E(&cfg, j);
|
||||||
if (false) {
|
j++;
|
||||||
// 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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// LDPC Rate matching
|
// 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;
|
output_ptr += E;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -617,3 +617,10 @@ if(RF_FOUND)
|
||||||
add_executable(prach_test_usrp prach_test_usrp.c)
|
add_executable(prach_test_usrp prach_test_usrp.c)
|
||||||
target_link_libraries(prach_test_usrp srslte_rf srslte_phy pthread)
|
target_link_libraries(prach_test_usrp srslte_rf srslte_phy pthread)
|
||||||
endif(RF_FOUND)
|
endif(RF_FOUND)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# NR
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
add_executable(dlsch_nr_test dlsch_nr_test.c)
|
||||||
|
target_link_libraries(dlsch_nr_test srslte_phy)
|
Loading…
Reference in New Issue