Refactored PDSCH/PUSCH decoder for LDPC early stopping

This commit is contained in:
Xavier Arteaga 2021-04-14 20:23:17 +02:00 committed by Xavier Arteaga
parent 6c5e28bc19
commit e4e3456d76
14 changed files with 267 additions and 224 deletions

View File

@ -150,4 +150,24 @@ srsran_ldpc_decoder_decode_s(srsran_ldpc_decoder_t* q, const int16_t* llrs, uint
SRSRAN_API int
srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q, const int8_t* llrs, uint8_t* message, uint32_t cdwd_rm_length);
/*!
* Carries out the actual decoding with 8-bit integer-valued LLRs. It is
* recommended to use a 7-bit representation for the LLRs, given that all
* values exceeding \f$ 2^{7}-1 \f$ (in magnitude) will be considered as infinity.
* \param[in] q A pointer to the LDPC decoder (a srsran_ldpc_decoder_t structure
* instance) that carries out the decoding.
* \param[in] llrs The LLRs obtained from the channel samples that correspond to
* the codeword to be decoded.
* \param[out] message The message (uncoded bits) resulting from the decoding
* operation.
* \param[in] cdwd_rm_length The number of bits forming the codeword (after rate matching).
* \param[in,out] crc Code-block CRC object for early stop. Set for NULL to disable check
* \return -1 if an error occurred, the number of used iterations, and 0 if CRC is provided and did not match
*/
SRSRAN_API int srsran_ldpc_decoder_decode_crc_c(srsran_ldpc_decoder_t* q,
const int8_t* llrs,
uint8_t* message,
uint32_t cdwd_rm_length,
srsran_crc_t* crc);
#endif // SRSRAN_LDPCDECODER_H

View File

@ -64,13 +64,11 @@ typedef struct SRSRAN_API {
} srsran_pdsch_nr_t;
/**
*
* @brief Groups NR-PDSCH data for reception
*/
typedef struct {
uint8_t* payload;
bool crc;
float evm;
uint32_t fec_iters;
srsran_sch_tb_res_nr_t tb[SRSRAN_MAX_TB]; ///< SCH payload
float evm[SRSRAN_MAX_CODEWORDS]; ///< EVM measurement if configured through arguments
} srsran_pdsch_res_nr_t;
SRSRAN_API int srsran_pdsch_nr_init_enb(srsran_pdsch_nr_t* q, const srsran_pdsch_nr_args_t* args);
@ -92,7 +90,7 @@ SRSRAN_API int srsran_pdsch_nr_decode(srsran_pdsch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
srsran_chest_dl_res_t* channel,
cf_t* sf_symbols[SRSRAN_MAX_PORTS],
srsran_pdsch_res_nr_t data[SRSRAN_MAX_TB]);
srsran_pdsch_res_nr_t* res);
SRSRAN_API uint32_t srsran_pdsch_nr_rx_info(const srsran_pdsch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,

View File

@ -70,18 +70,17 @@ typedef struct SRSRAN_API {
* @brief Groups NR-PUSCH data for transmission
*/
typedef struct {
uint8_t* payload; ///< SCH payload
srsran_uci_value_nr_t uci; ///< UCI payload
uint8_t* payload[SRSRAN_MAX_TB]; ///< SCH payload
srsran_uci_value_nr_t uci; ///< UCI payload
} srsran_pusch_data_nr_t;
/**
* @brief Groups NR-PUSCH data for reception
*/
typedef struct {
uint8_t* payload; ///< SCH payload
srsran_uci_value_nr_t uci; ///< UCI payload
bool crc; ///< CRC match
float evm; ///< EVM measurement if configured through arguments
srsran_sch_tb_res_nr_t tb[SRSRAN_MAX_TB]; ///< SCH payload
srsran_uci_value_nr_t uci; ///< UCI payload
float evm[SRSRAN_MAX_CODEWORDS]; ///< EVM measurement if configured through arguments
} srsran_pusch_res_nr_t;
SRSRAN_API int srsran_pusch_nr_init_gnb(srsran_pusch_nr_t* q, const srsran_pusch_nr_args_t* args);

View File

@ -32,6 +32,15 @@
#define SRSRAN_SCH_NR_MAX_NOF_CB_LDPC \
((SRSRAN_SLOT_MAX_NOF_BITS_NR + (SRSRAN_LDPC_BG2_MAX_LEN_CB - 1)) / SRSRAN_LDPC_BG2_MAX_LEN_CB)
/**
* @brief Groups NR-PUSCH data for reception
*/
typedef struct {
uint8_t* payload; ///< SCH payload
bool crc; ///< CRC match
float avg_iter; ///< Average iterations
} srsran_sch_tb_res_nr_t;
typedef struct SRSRAN_API {
srsran_carrier_nr_t carrier;
@ -153,8 +162,7 @@ SRSRAN_API int srsran_dlsch_nr_decode(srsran_sch_nr_t* q,
const srsran_sch_cfg_t* sch_cfg,
const srsran_sch_tb_t* tb,
int8_t* e_bits,
uint8_t* data,
bool* crc_ok);
srsran_sch_tb_res_nr_t* res);
SRSRAN_API int srsran_ulsch_nr_encode(srsran_sch_nr_t* q,
const srsran_sch_cfg_t* cfg,
@ -166,9 +174,9 @@ SRSRAN_API int srsran_ulsch_nr_decode(srsran_sch_nr_t* q,
const srsran_sch_cfg_t* sch_cfg,
const srsran_sch_tb_t* tb,
int8_t* e_bits,
uint8_t* data,
bool* crc_ok);
srsran_sch_tb_res_nr_t* res);
SRSRAN_API int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, char* str, uint32_t str_len);
SRSRAN_API 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);
#endif // SRSRAN_SCH_NR_H

View File

@ -73,11 +73,24 @@
update_ldpc_check_to_var_##SUFFIX(q->ptr, i_layer, this_pcm, these_var_indices); \
\
update_ldpc_soft_bits_##SUFFIX(q->ptr, i_layer, these_var_indices); \
} \
\
if (crc != NULL) { \
extract_ldpc_message_##SUFFIX(q->ptr, message, q->liftK); \
\
if (srsran_crc_match(crc, message, q->liftK - crc->order)) { \
return i_iteration + 1; \
} \
} \
} \
\
extract_ldpc_message_##SUFFIX(q->ptr, message, q->liftK); \
/* If reached here, and CRC is being checked, it has failed */ \
if (crc != NULL) { \
return 0; \
} \
\
/* Without CRC, extract message and return the maximum number of iterations */ \
extract_ldpc_message_##SUFFIX(q->ptr, message, q->liftK); \
return q->max_nof_iter; \
}
#define LDPC_DECODER_TEMPLATE_FLOOD(LLR_TYPE, SUFFIX) \
@ -638,3 +651,12 @@ int srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q,
{
return q->decode_c(q, llrs, message, cdwd_rm_length, NULL);
}
int srsran_ldpc_decoder_decode_crc_c(srsran_ldpc_decoder_t* q,
const int8_t* llrs,
uint8_t* message,
uint32_t cdwd_rm_length,
srsran_crc_t* crc)
{
return q->decode_c(q, llrs, message, cdwd_rm_length, crc);
}

View File

@ -462,7 +462,8 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q,
// EVM
if (q->evm_buffer != NULL) {
res->evm = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
res->evm[tb->cw_idx] =
srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
}
// Change LLR sign and set to zero the LLR that are not used
@ -477,7 +478,7 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q,
}
// Decode SCH
if (srsran_dlsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSRAN_SUCCESS) {
if (srsran_dlsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) {
ERROR("Error in DL-SCH encoding");
return SRSRAN_ERROR;
}
@ -566,10 +567,12 @@ int srsran_pdsch_nr_decode(srsran_pdsch_nr_t* q,
return SRSRAN_SUCCESS;
}
static uint32_t srsran_pdsch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
char* str,
uint32_t str_len)
static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pdsch_res_nr_t* res,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
len = srsran_print_check(str, str_len, len, "rnti=0x%x ", grant->rnti);
@ -606,7 +609,15 @@ static uint32_t srsran_pdsch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
// Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
len += srsran_sch_nr_tb_info(&grant->tb[i], &str[len], str_len - len);
len += srsran_sch_nr_tb_info(&grant->tb[i], &res->tb[i], &str[len], str_len - len);
if (res != NULL) {
if (grant->tb[i].enabled && !isnan(res->evm[i])) {
len = srsran_print_check(str, str_len, len, "evm=%.2f ", res->evm[i]);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
}
}
}
}
return len;
@ -615,52 +626,21 @@ static uint32_t srsran_pdsch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
uint32_t srsran_pdsch_nr_rx_info(const srsran_pdsch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS],
const srsran_pdsch_res_nr_t* res,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
len += srsran_pdsch_nr_grant_info(cfg, grant, &str[len], str_len - len);
len += pdsch_nr_grant_info(q, cfg, grant, res, &str[len], str_len - len);
if (cfg->rvd_re.count != 0) {
len = srsran_print_check(str, str_len, len, ", Reserved={");
len = srsran_print_check(str, str_len, len, "Reserved: ");
len += srsran_re_pattern_list_info(&cfg->rvd_re, &str[len], str_len - len);
len = srsran_print_check(str, str_len, len, "}");
}
if (q->evm_buffer != NULL) {
len = srsran_print_check(str, str_len, len, ",evm={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled && !isnan(res[i].evm)) {
len = srsran_print_check(str, str_len, len, "%.2f", res[i].evm);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, ",", 0);
}
}
}
}
len = srsran_print_check(str, str_len, len, "}", 0);
}
if (res != NULL) {
len = srsran_print_check(str, str_len, len, ",crc={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled) {
len = srsran_print_check(str, str_len, len, "%s", res[i].crc ? "OK" : "KO");
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, ",", 0);
}
}
}
}
len = srsran_print_check(str, str_len, len, "}", 0);
}
if (q->meas_time_en) {
len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us);
len = srsran_print_check(str, str_len, len, " t=%d us", q->meas_time_us);
}
return len;

View File

@ -961,7 +961,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
nof_cw += grant->tb[tb].enabled ? 1 : 0;
if (pusch_nr_encode_codeword(q, cfg, &grant->tb[tb], data[tb].payload, &data[0].uci, grant->rnti) <
if (pusch_nr_encode_codeword(q, cfg, &grant->tb[tb], data->payload[tb], &data[0].uci, grant->rnti) <
SRSRAN_SUCCESS) {
ERROR("Error encoding TB %d", tb);
return SRSRAN_ERROR;
@ -1064,7 +1064,8 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// EVM
if (q->evm_buffer != NULL) {
res->evm = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
res->evm[tb->cw_idx] =
srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
}
// Descrambling
@ -1133,7 +1134,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Decode Ul-SCH
if (tb->nof_bits != 0) {
if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSRAN_SUCCESS) {
if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) {
ERROR("Error in SCH decoding");
return SRSRAN_ERROR;
}
@ -1231,6 +1232,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
{
@ -1267,7 +1269,7 @@ static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
// Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
len += srsran_sch_nr_tb_info(&grant->tb[i], &str[len], str_len - len);
len += srsran_sch_nr_tb_info(&grant->tb[i], &res->tb[i], &str[len], str_len - len);
}
return len;
@ -1276,7 +1278,7 @@ static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pusch_res_nr_t res[SRSRAN_MAX_CODEWORDS],
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
{
@ -1286,12 +1288,12 @@ uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
return 0;
}
len += srsran_pusch_nr_grant_info(cfg, grant, &str[len], str_len - len);
len += srsran_pusch_nr_grant_info(cfg, grant, res, &str[len], str_len - len);
if (q->evm_buffer != NULL) {
len = srsran_print_check(str, str_len, len, ",evm={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled && !isnan(res[i].evm)) {
if (grant->tb[i].enabled && !isnan(res->evm[i])) {
len = srsran_print_check(str, str_len, len, "%.2f", res[i].evm);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
@ -1312,7 +1314,7 @@ uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
len = srsran_print_check(str, str_len, len, ",crc={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled) {
len = srsran_print_check(str, str_len, len, "%s", res[i].crc ? "OK" : "KO");
len = srsran_print_check(str, str_len, len, "%s", res->tb[i].crc ? "OK" : "KO");
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, ",", 0);
@ -1343,7 +1345,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q,
return 0;
}
len += srsran_pusch_nr_grant_info(cfg, grant, &str[len], str_len - len);
len += srsran_pusch_nr_grant_info(cfg, grant, NULL, &str[len], str_len - len);
if (uci_value != NULL) {
srsran_uci_data_nr_t uci_data = {};

View File

@ -509,19 +509,19 @@ static inline int sch_nr_encode(srsran_sch_nr_t* q,
return SRSRAN_SUCCESS;
}
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,
uint8_t* data,
bool* crc_ok)
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)
{
// Pointer protection
if (!q || !sch_cfg || !tb || !data || !e_bits || !crc_ok) {
if (!q || !sch_cfg || !tb || !e_bits || !res) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
int8_t* input_ptr = e_bits;
int8_t* input_ptr = e_bits;
uint32_t nof_iter_sum = 0;
srsran_sch_nr_tb_info_t cfg = {};
if (srsran_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSRAN_SUCCESS) {
@ -599,27 +599,25 @@ int sch_nr_decode(srsran_sch_nr_t* q,
return SRSRAN_ERROR;
}
// Decode
srsran_ldpc_decoder_decode_c(decoder, rm_buffer, q->temp_cb, n_llr);
// Compute CB CRC
uint32_t cb_len = cfg.Kp - cfg.L_cb;
// Select CB or TB early stop CRC
srsran_crc_t* crc = (cfg.L_tb == 16) ? &q->crc_tb_16 : &q->crc_tb_24;
if (cfg.L_cb) {
uint8_t* ptr = q->temp_cb + cb_len;
uint32_t checksum1 = srsran_crc_checksum(&q->crc_cb, q->temp_cb, (int)cb_len);
uint32_t checksum2 = srsran_bit_pack(&ptr, cfg.L_cb);
tb->softbuffer.rx->cb_crc[r] = (checksum1 == checksum2);
SCH_INFO_RX("CB %d/%d: CRC={%06x, %06x} ... %s",
r,
cfg.C,
checksum1,
checksum2,
tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO");
} else {
tb->softbuffer.rx->cb_crc[r] = true;
crc = &q->crc_cb;
}
// Decode
int n_iter = srsran_ldpc_decoder_decode_crc_c(decoder, rm_buffer, q->temp_cb, n_llr, crc);
if (n_iter < SRSRAN_SUCCESS) {
ERROR("Error decoding CB");
return SRSRAN_ERROR;
}
nof_iter_sum += ((n_iter == 0) ? decoder->max_nof_iter : (uint32_t)n_iter);
// Compute CB CRC only if LDPC decoder reached the end
uint32_t cb_len = cfg.Kp - cfg.L_cb;
tb->softbuffer.rx->cb_crc[r] = (n_iter != 0);
SCH_INFO_RX("CB %d/%d CRC=%s", r, cfg.C, tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO");
// Pack and count CRC OK only if CRC is match
if (tb->softbuffer.rx->cb_crc[r]) {
srsran_bit_pack_vector(q->temp_cb, tb->softbuffer.rx->data[r], cb_len);
@ -629,51 +627,64 @@ int sch_nr_decode(srsran_sch_nr_t* q,
input_ptr += E;
}
// All CB are decoded
if (cb_ok == cfg.C) {
uint32_t checksum2 = 0;
uint8_t* output_ptr = data;
// Not all CB are decoded, skip TB union and CRC check
if (cb_ok != cfg.C) {
return SRSRAN_SUCCESS;
}
for (uint32_t r = 0; r < cfg.C; r++) {
uint32_t cb_len = cfg.Kp - cfg.L_cb;
uint32_t checksum2 = 0;
uint8_t* output_ptr = res->payload;
// Subtract TB CRC from the last code block
if (r == cfg.C - 1) {
cb_len -= cfg.L_tb;
}
for (uint32_t r = 0; r < cfg.C; r++) {
uint32_t cb_len = cfg.Kp - cfg.L_cb;
srsran_vec_u8_copy(output_ptr, tb->softbuffer.rx->data[r], cb_len / 8);
output_ptr += cb_len / 8;
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("CB %d:", r);
srsran_vec_fprint_byte(stdout, tb->softbuffer.rx->data[r], cb_len / 8);
}
if (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);
}
// Subtract TB CRC from the last code block
if (r == cfg.C - 1) {
cb_len -= cfg.L_tb;
}
// Check if TB is all zeros
bool all_zeros = true;
for (uint32_t i = 0; i < tb->tbs / 8 && all_zeros; i++) {
all_zeros = (data[i] == 0);
}
// Append CB
srsran_vec_u8_copy(output_ptr, tb->softbuffer.rx->data[r], cb_len / 8);
output_ptr += cb_len / 8;
// Calculate TB CRC from packed data
uint32_t checksum1 = srsran_crc_checksum_byte(crc_tb, data, tb->tbs);
*crc_ok = (checksum1 == checksum2 && !all_zeros);
SCH_INFO_RX("TB: TBS=%d; CRC={%06x, %06x}", tb->tbs, checksum1, checksum2);
// CB Debug trace
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("Decode: ");
srsran_vec_fprint_byte(stdout, data, tb->tbs / 8);
DEBUG("CB %d/%d:", r, cfg.C);
srsran_vec_fprint_byte(stdout, tb->softbuffer.rx->data[r], 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);
}
}
// Check if TB is all zeros
bool all_zeros = true;
for (uint32_t i = 0; i < tb->tbs / 8 && all_zeros; i++) {
all_zeros = (res->payload[i] == 0);
}
// Calculate TB CRC from packed data
if (cfg.C == 1) {
res->crc = !all_zeros;
SCH_INFO_RX("TB: TBS=%d; CRC=%s", tb->tbs, tb->softbuffer.rx->cb_crc[0] ? "OK" : "KO");
} else {
*crc_ok = false;
// More than one
uint32_t checksum1 = srsran_crc_checksum_byte(crc_tb, res->payload, tb->tbs);
res->crc = (checksum1 == checksum2 && !all_zeros);
SCH_INFO_RX("TB: TBS=%d; CRC={%06x, %06x}", tb->tbs, checksum1, checksum2);
}
// Set average number of iterations
res->avg_iter = (float)nof_iter_sum / (float)cfg.C;
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("Decode: ");
srsran_vec_fprint_byte(stdout, res->payload, tb->tbs / 8);
}
return SRSRAN_SUCCESS;
@ -692,10 +703,9 @@ int srsran_dlsch_nr_decode(srsran_sch_nr_t* q,
const srsran_sch_cfg_t* sch_cfg,
const srsran_sch_tb_t* tb,
int8_t* e_bits,
uint8_t* data,
bool* crc_ok)
srsran_sch_tb_res_nr_t* res)
{
return sch_nr_decode(q, sch_cfg, tb, e_bits, data, crc_ok);
return sch_nr_decode(q, sch_cfg, tb, e_bits, res);
}
int srsran_ulsch_nr_encode(srsran_sch_nr_t* q,
@ -711,30 +721,33 @@ int srsran_ulsch_nr_decode(srsran_sch_nr_t* q,
const srsran_sch_cfg_t* sch_cfg,
const srsran_sch_tb_t* tb,
int8_t* e_bits,
uint8_t* data,
bool* crc_ok)
srsran_sch_tb_res_nr_t* res)
{
return sch_nr_decode(q, sch_cfg, tb, e_bits, data, crc_ok);
return sch_nr_decode(q, sch_cfg, tb, e_bits, res);
}
int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, char* str, uint32_t str_len)
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)
{
int len = 0;
if (tb->enabled) {
len += srsran_print_check(str,
str_len,
len,
"CW0: mod=%s Nl=%d tbs=%d R=%.3f rv=%d Nre=%d Nbit=%d cw=%d",
srsran_mod_string(tb->mod),
tb->N_L,
tb->tbs / 8,
tb->R,
tb->rv,
tb->nof_re,
tb->nof_bits,
tb->cw_idx);
len = srsran_print_check(str,
str_len,
len,
"CW%d: mod=%s Nl=%d tbs=%d R=%.3f rv=%d Nre=%d Nbit=%d ",
tb->cw_idx,
srsran_mod_string(tb->mod),
tb->N_L,
tb->tbs / 8,
tb->R,
tb->rv,
tb->nof_re,
tb->nof_bits);
if (res != NULL) {
len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter);
}
}
return len;
}
}

View File

@ -75,12 +75,12 @@ int parse_args(int argc, char** argv)
int main(int argc, char** argv)
{
int ret = SRSRAN_ERROR;
srsran_pdsch_nr_t pdsch_tx = {};
srsran_pdsch_nr_t pdsch_rx = {};
srsran_chest_dl_res_t chest = {};
srsran_pdsch_res_nr_t pdsch_res[SRSRAN_MAX_TB] = {};
srsran_random_t rand_gen = srsran_random_init(1234);
int ret = SRSRAN_ERROR;
srsran_pdsch_nr_t pdsch_tx = {};
srsran_pdsch_nr_t pdsch_rx = {};
srsran_chest_dl_res_t chest = {};
srsran_pdsch_res_nr_t pdsch_res = {};
srsran_random_t rand_gen = srsran_random_init(1234);
uint8_t* data_tx[SRSRAN_MAX_TB] = {};
uint8_t* data_rx[SRSRAN_MAX_CODEWORDS] = {};
@ -133,7 +133,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
pdsch_res[i].payload = data_rx[i];
pdsch_res.tb[i].payload = data_rx[i];
}
srsran_softbuffer_tx_t softbuffer_tx = {};
@ -224,14 +224,14 @@ int main(int argc, char** argv)
}
chest.nof_re = pdsch_cfg.grant.tb->nof_re;
if (srsran_pdsch_nr_decode(&pdsch_rx, &pdsch_cfg, &pdsch_cfg.grant, &chest, sf_symbols, pdsch_res) <
if (srsran_pdsch_nr_decode(&pdsch_rx, &pdsch_cfg, &pdsch_cfg.grant, &chest, sf_symbols, &pdsch_res) <
SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
if (pdsch_res->evm > 0.001f) {
ERROR("Error PDSCH EVM is too high %f", pdsch_res->evm);
if (pdsch_res.evm[0] > 0.001f) {
ERROR("Error PDSCH EVM is too high %f", pdsch_res.evm[0]);
goto clean_exit;
}
@ -256,7 +256,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
if (!pdsch_res[0].crc) {
if (!pdsch_res.tb[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
goto clean_exit;
}
@ -270,7 +270,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res[0].evm);
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res.evm[0]);
}
}

View File

@ -90,8 +90,8 @@ int main(int argc, char** argv)
srsran_chest_dl_res_t chest = {};
srsran_random_t rand_gen = srsran_random_init(1234);
srsran_pusch_data_nr_t data_tx[SRSRAN_MAX_TB] = {};
srsran_pusch_res_nr_t data_rx[SRSRAN_MAX_CODEWORDS] = {};
srsran_pusch_data_nr_t data_tx = {};
srsran_pusch_res_nr_t data_rx = {};
cf_t* sf_symbols[SRSRAN_MAX_LAYERS_NR] = {};
// Set default PUSCH configuration
@ -134,9 +134,9 @@ int main(int argc, char** argv)
}
for (uint32_t i = 0; i < pusch_tx.max_cw; i++) {
data_tx[i].payload = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR);
data_rx[i].payload = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR);
if (data_tx[i].payload == NULL || data_rx[i].payload == NULL) {
data_tx.payload[i] = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR);
data_rx.tb[i].payload = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR);
if (data_tx.payload[i] == NULL || data_rx.tb[i].payload == NULL) {
ERROR("Error malloc");
goto clean_exit;
}
@ -212,12 +212,12 @@ int main(int argc, char** argv)
// Generate SCH payload
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
// Skip TB if no allocated
if (data_tx[tb].payload == NULL) {
if (data_tx.payload[tb] == NULL) {
continue;
}
for (uint32_t i = 0; i < pusch_cfg.grant.tb[tb].tbs; i++) {
data_tx[tb].payload[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
data_tx.payload[tb][i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
}
pusch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx;
}
@ -226,7 +226,7 @@ int main(int argc, char** argv)
if (nof_ack_bits > 0) {
pusch_cfg.uci.o_ack = nof_ack_bits;
for (uint32_t i = 0; i < nof_ack_bits; i++) {
data_tx->uci.ack[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1);
data_tx.uci.ack[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1);
}
}
@ -237,15 +237,15 @@ int main(int argc, char** argv)
pusch_cfg.uci.csi[0].quantity = SRSRAN_CSI_REPORT_QUANTITY_NONE;
pusch_cfg.uci.csi[0].K_csi_rs = nof_csi_bits;
pusch_cfg.uci.nof_csi = 1;
data_tx->uci.csi[0].none = csi_report_tx;
data_tx.uci.csi[0].none = csi_report_tx;
for (uint32_t i = 0; i < nof_csi_bits; i++) {
csi_report_tx[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1);
}
data_rx->uci.csi[0].none = csi_report_rx;
data_rx.uci.csi[0].none = csi_report_rx;
}
if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, data_tx, sf_symbols) < SRSRAN_SUCCESS) {
if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols) < SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
@ -260,14 +260,14 @@ int main(int argc, char** argv)
}
chest.nof_re = pusch_cfg.grant.tb->nof_re;
if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, data_rx) <
if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, &data_rx) <
SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
if (data_rx[0].evm > 0.001f) {
ERROR("Error PUSCH EVM is too high %f", data_rx[0].evm);
if (data_rx.evm[0] > 0.001f) {
ERROR("Error PUSCH EVM is too high %f", data_rx.evm[0]);
goto clean_exit;
}
@ -293,24 +293,24 @@ int main(int argc, char** argv)
}
// Validate UL-SCH CRC check
if (!data_rx[0].crc) {
if (!data_rx.tb[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs);
goto clean_exit;
}
// Validate UL-SCH payload
if (memcmp(data_tx[0].payload, data_rx[0].payload, pusch_cfg.grant.tb[0].tbs / 8) != 0) {
if (memcmp(data_tx.payload[0], data_rx.tb[0].payload, pusch_cfg.grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs);
printf("Tx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs / 8);
printf("Rx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs / 8);
goto clean_exit;
}
// Validate UCI is decoded successfully
if (nof_ack_bits > 0 || nof_csi_bits > 0) {
if (!data_rx[0].uci.valid) {
if (!data_rx.uci.valid) {
ERROR("UCI data was not decoded ok");
goto clean_exit;
}
@ -318,29 +318,29 @@ int main(int argc, char** argv)
// Validate HARQ-ACK is decoded successfully
if (nof_ack_bits > 0) {
if (memcmp(data_tx[0].uci.ack, data_rx[0].uci.ack, nof_ack_bits) != 0) {
if (memcmp(data_tx.uci.ack, data_rx.uci.ack, nof_ack_bits) != 0) {
ERROR("UCI HARQ-ACK bits are unmatched");
printf("Tx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0].uci.ack, nof_ack_bits);
srsran_vec_fprint_byte(stdout, data_tx.uci.ack, nof_ack_bits);
printf("Rx data: ");
srsran_vec_fprint_byte(stdout, data_rx[0].uci.ack, nof_ack_bits);
srsran_vec_fprint_byte(stdout, data_rx.uci.ack, nof_ack_bits);
goto clean_exit;
}
}
// Validate CSI is decoded successfully
if (nof_csi_bits > 0) {
if (memcmp(data_tx[0].uci.csi[0].none, data_rx[0].uci.csi[0].none, nof_csi_bits) != 0) {
if (memcmp(data_tx.uci.csi[0].none, data_rx.uci.csi[0].none, nof_csi_bits) != 0) {
ERROR("UCI CSI bits are unmatched");
printf("Tx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0].uci.csi[0].none, nof_csi_bits);
srsran_vec_fprint_byte(stdout, data_tx.uci.csi[0].none, nof_csi_bits);
printf("Rx data: ");
srsran_vec_fprint_byte(stdout, data_rx[0].uci.csi[0].none, nof_csi_bits);
srsran_vec_fprint_byte(stdout, data_rx.uci.csi[0].none, nof_csi_bits);
goto clean_exit;
}
}
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx[0].evm);
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx.evm[0]);
}
}
@ -352,11 +352,11 @@ clean_exit:
srsran_pusch_nr_free(&pusch_tx);
srsran_pusch_nr_free(&pusch_rx);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (data_tx[i].payload) {
free(data_tx[i].payload);
if (data_tx.payload[i]) {
free(data_tx.payload[i]);
}
if (data_rx[i].payload) {
free(data_rx[i].payload);
if (data_rx.tb[i].payload) {
free(data_rx.tb[i].payload);
}
}
for (uint32_t i = 0; i < SRSRAN_MAX_LAYERS_NR; i++) {

View File

@ -206,14 +206,15 @@ int main(int argc, char** argv)
tb.softbuffer.rx = &softbuffer_rx;
srsran_softbuffer_rx_reset(tb.softbuffer.rx);
bool crc = false;
if (srsran_dlsch_nr_decode(&sch_nr_rx, &pdsch_cfg.sch_cfg, &tb, llr, data_rx, &crc) < SRSRAN_SUCCESS) {
srsran_sch_tb_res_nr_t res = {};
res.payload = data_rx;
if (srsran_dlsch_nr_decode(&sch_nr_rx, &pdsch_cfg.sch_cfg, &tb, llr, &res) < SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
if (rv == 0) {
if (!crc) {
if (!res.crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, tb.tbs);
goto clean_exit;
}

View File

@ -585,7 +585,7 @@ int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q,
len += srsran_pdsch_nr_rx_info(&q->pdsch, cfg, &cfg->grant, res, &str[len], str_len - len);
// Append channel estimator info
len = srsran_print_check(str, str_len, len, ",SNR=%+.1f", q->chest.snr_db);
len = srsran_print_check(str, str_len, len, "SNR=%+.1f", q->chest.snr_db);
return len;
}

View File

@ -184,16 +184,16 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot, srsran_
int main(int argc, char** argv)
{
int ret = SRSRAN_ERROR;
srsran_enb_dl_nr_t enb_dl = {};
srsran_ue_dl_nr_t ue_dl = {};
srsran_pdsch_res_nr_t pdsch_res[SRSRAN_MAX_TB] = {};
srsran_random_t rand_gen = srsran_random_init(1234);
srsran_slot_cfg_t slot = {};
struct timeval t[3] = {};
uint64_t pdsch_encode_us = 0;
uint64_t pdsch_decode_us = 0;
uint64_t nof_bits = 0;
int ret = SRSRAN_ERROR;
srsran_enb_dl_nr_t enb_dl = {};
srsran_ue_dl_nr_t ue_dl = {};
srsran_pdsch_res_nr_t pdsch_res = {};
srsran_random_t rand_gen = srsran_random_init(1234);
srsran_slot_cfg_t slot = {};
struct timeval t[3] = {};
uint64_t pdsch_encode_us = 0;
uint64_t pdsch_decode_us = 0;
uint64_t nof_bits = 0;
uint8_t* data_tx[SRSRAN_MAX_TB] = {};
uint8_t* data_rx[SRSRAN_MAX_CODEWORDS] = {};
@ -296,7 +296,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
pdsch_res[i].payload = data_rx[i];
pdsch_res.tb[i].payload = data_rx[i];
}
srsran_softbuffer_tx_t softbuffer_tx = {};
@ -418,7 +418,7 @@ int main(int argc, char** argv)
}
gettimeofday(&t[1], NULL);
if (work_ue_dl(&ue_dl, &slot, pdsch_res) < SRSRAN_SUCCESS) {
if (work_ue_dl(&ue_dl, &slot, &pdsch_res) < SRSRAN_SUCCESS) {
ERROR("Error running UE DL");
goto clean_exit;
}
@ -426,14 +426,14 @@ int main(int argc, char** argv)
get_time_interval(t);
pdsch_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
if (pdsch_res->evm > 0.02f) {
ERROR("Error PDSCH EVM is too high %f", pdsch_res->evm);
if (pdsch_res.evm[0] > 0.02f) {
ERROR("Error PDSCH EVM is too high %f", pdsch_res.evm[0]);
goto clean_exit;
}
// Check CRC only for RV=0
if (rv_idx == 0) {
if (!pdsch_res[0].crc) {
if (!pdsch_res.tb[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
goto clean_exit;
}
@ -448,7 +448,7 @@ int main(int argc, char** argv)
}
}
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res[0].evm);
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res.evm[0]);
// Count the Tx/Rx'd number of bits
nof_bits += pdsch_cfg.grant.tb[0].tbs;

View File

@ -253,12 +253,12 @@ bool cc_worker::work_dl()
srsran_softbuffer_rx_reset(&softbuffer_rx);
// Initialise PDSCH Result
std::array<srsran_pdsch_res_nr_t, SRSRAN_MAX_CODEWORDS> pdsch_res = {};
pdsch_res[0].payload = data->msg;
pdsch_cfg.grant.tb[0].softbuffer.rx = &softbuffer_rx;
srsran_pdsch_res_nr_t pdsch_res = {};
pdsch_res.tb[0].payload = data->msg;
pdsch_cfg.grant.tb[0].softbuffer.rx = &softbuffer_rx;
// Decode actual PDSCH transmission
if (srsran_ue_dl_nr_decode_pdsch(&ue_dl, &dl_slot_cfg, &pdsch_cfg, pdsch_res.data()) < SRSRAN_SUCCESS) {
if (srsran_ue_dl_nr_decode_pdsch(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_res) < SRSRAN_SUCCESS) {
ERROR("Error decoding PDSCH");
return false;
}
@ -266,17 +266,17 @@ bool cc_worker::work_dl()
// Logging
if (logger.info.enabled()) {
std::array<char, 512> str;
srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, pdsch_res.data(), str.data(), str.size());
logger.info(pdsch_res[0].payload, pdsch_cfg.grant.tb[0].tbs / 8, "PDSCH: cc=%d, %s", cc_idx, str.data());
srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str.data(), str.size());
logger.info(pdsch_res.tb[0].payload, pdsch_cfg.grant.tb[0].tbs / 8, "PDSCH: cc=%d, %s", cc_idx, str.data());
}
// Enqueue PDSCH ACK information only if the RNTI is type C
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_c) {
phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res[0].crc);
phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res.tb[0].crc);
}
// Notify MAC about PDSCH decoding result
if (pdsch_res[0].crc) {
if (pdsch_res.tb[0].crc) {
// Prepare grant
mac_interface_phy_nr::mac_nr_grant_dl_t mac_nr_grant = {};
mac_nr_grant.tb[0] = std::move(data);
@ -294,8 +294,8 @@ bool cc_worker::work_dl()
// Generate DL metrics
dl_metrics_t dl_m = {};
dl_m.mcs = pdsch_cfg.grant.tb[0].mcs;
dl_m.fec_iters = pdsch_res[0].fec_iters;
dl_m.evm = pdsch_res[0].evm;
dl_m.fec_iters = pdsch_res.tb[0].avg_iter;
dl_m.evm = pdsch_res.evm[0];
phy->set_dl_metrics(dl_m);
// Generate Synch metrics
@ -386,7 +386,7 @@ bool cc_worker::work_ul()
// Setup data for encoding
srsran_pusch_data_nr_t data = {};
data.payload = ul_action.tb.payload->msg;
data.payload[0] = ul_action.tb.payload->msg;
data.uci = uci_data.value;
// Encode PUSCH transmission