diff --git a/lib/src/phy/fec/cbsegm.c b/lib/src/phy/fec/cbsegm.c index 0ed03393e..f9f0fbb2a 100644 --- a/lib/src/phy/fec/cbsegm.c +++ b/lib/src/phy/fec/cbsegm.c @@ -160,12 +160,12 @@ bool srslte_cbsegm_cbsize_isvalid(uint32_t size) static int cbsegm_ldpc_select_ls(uint32_t Kp, uint32_t K_b, uint32_t* Z_c, uint8_t* i_ls) { // Early return if the minimum required lift size is too high - if (Kp / K_b > MAX_LIFTSIZE) { + if (CEIL(Kp, K_b) > MAX_LIFTSIZE) { return SRSLTE_ERROR; } // 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 = CEIL(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/sch_nr.c b/lib/src/phy/phch/sch_nr.c index f63a17a64..e9967d795 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -85,7 +85,7 @@ int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q, // Compute code block segmentation srslte_cbsegm_t cbsegm = {}; - if (cfg->bg == BG1) { + if (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; @@ -180,7 +180,7 @@ static inline int sch_nr_init_common(srslte_sch_nr_t* q) } if (!q->temp_cb) { - q->temp_cb = srslte_vec_u8_malloc(SRSLTE_LDPC_MAX_LEN_CB); + q->temp_cb = srslte_vec_u8_malloc(SRSLTE_LDPC_MAX_LEN_CB * 8); if (!q->temp_cb) { return SRSLTE_ERROR; } @@ -416,6 +416,7 @@ int srslte_dlsch_nr_encode(srslte_sch_nr_t* q, // Append TB CRC uint8_t* ptr = &q->temp_cb[cfg.Kp - cfg.L_cb - cfg.L_tb]; srslte_bit_unpack(checksum_tb, &ptr, cfg.L_tb); + INFO("CB %d: appending TB CRC=%06x\n", r, checksum_tb); } else { // Copy payload srslte_bit_unpack_vector(data, q->temp_cb, (int)(cfg.Kp - cfg.L_cb)); @@ -424,6 +425,7 @@ int srslte_dlsch_nr_encode(srslte_sch_nr_t* q, // Attach code block CRC if required if (cfg.L_cb) { srslte_crc_attach(&q->crc_cb, q->temp_cb, (int)(cfg.Kp - cfg.L_cb)); + INFO("CB %d: CRC=%06x\n", r, (uint32_t)srslte_crc_checksum_get(&q->crc_cb)); } // Insert filler bits @@ -445,6 +447,15 @@ int srslte_dlsch_nr_encode(srslte_sch_nr_t* q, j++; // LDPC Rate matching + INFO("RM CB %d: E=%d; F=%d; BG=%d; Z=%d; RV=%d; Qm=%d; Nref=%d;\n", + r, + E, + cfg.F, + cfg.bg == BG1 ? 1 : 2, + cfg.Z, + tb->rv, + cfg.Qm, + cfg.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; } @@ -512,6 +523,15 @@ int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, j++; // LDPC Rate matching + INFO("RM CB %d: E=%d; F=%d; BG=%d; Z=%d; RV=%d; Qm=%d; Nref=%d;\n", + r, + E, + cfg.F, + cfg.bg == BG1 ? 1 : 2, + cfg.Z, + tb->rv, + cfg.Qm, + cfg.Nref); 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 @@ -525,6 +545,12 @@ int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, uint32_t checksum2 = srslte_bit_pack(&ptr, cfg.L_cb); tb->softbuffer.rx->cb_crc[r] = (checksum1 == checksum2); + INFO("CB %d: CRC={%06x, %06x} ... %s\n", + r, + checksum1, + checksum2, + tb->softbuffer.rx->cb_crc[r] ? "OK" : "KOtb->softbuffer.rx->cb_crc[r]"); + // 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); @@ -566,6 +592,9 @@ int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, // Calculate TB CRC from packed data uint32_t checksum1 = srslte_crc_checksum_byte(cfg.crc_tb, data, tb->tbs); *crc_ok = (checksum1 == checksum2); + + INFO("TB: TBS=%d; CRC={%06x, %06x}\n", tb->tbs, checksum1, checksum2); + // srslte_vec_fprint_byte(stdout, data, tb->tbs / 8); } else { *crc_ok = false; } diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index dff195f78..e1f16c33e 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -623,4 +623,5 @@ endif(RF_FOUND) ######################################################################## add_executable(dlsch_nr_test dlsch_nr_test.c) -target_link_libraries(dlsch_nr_test srslte_phy) \ No newline at end of file +target_link_libraries(dlsch_nr_test srslte_phy) +add_test(dlsch_nr_test dlsch_nr_test) diff --git a/lib/src/phy/phch/test/dlsch_nr_test.c b/lib/src/phy/phch/test/dlsch_nr_test.c new file mode 100644 index 000000000..33a394925 --- /dev/null +++ b/lib/src/phy/phch/test/dlsch_nr_test.c @@ -0,0 +1,237 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/phy/phch/sch_nr.h" +#include "srslte/phy/ue/ue_dl_nr_data.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include +#include + +static srslte_carrier_nr_t carrier = { + 0, // cell_id + 0, // numerology + SRSLTE_MAX_PRB_NR, // nof_prb + 0 // start +}; + +static uint32_t n_prb = 1; // Set to 0 for steering +static uint32_t mcs = 16; // Set to 30 for steering +static srslte_pdsch_cfg_nr_t pdsch_cfg = {}; +static srslte_pdsch_grant_nr_t pdsch_grant = {}; + +void usage(char* prog) +{ + printf("Usage: %s [pTL] \n", prog); + printf("\t-p Number of carrier PRB [Default %d]\n", carrier.nof_prb); + printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", + srslte_mcs_table_to_str(pdsch_cfg.mcs_table)); + printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.serving_cell_cfg.max_mimo_layers); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +int parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "pTLv")) != -1) { + switch (opt) { + case 'p': + carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'T': + pdsch_cfg.mcs_table = srslte_mcs_table_from_str(argv[optind]); + break; + case 'L': + pdsch_cfg.serving_cell_cfg.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + return SRSLTE_ERROR; + } + } + srslte_verbose++; + + return SRSLTE_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSLTE_ERROR; + srslte_sch_nr_t sch_nr_tx = {}; + srslte_sch_nr_t sch_nr_rx = {}; + srslte_random_t rand_gen = srslte_random_init(1234); + + uint8_t* data_tx = srslte_vec_u8_malloc(1024 * 1024); + uint8_t* encoded = srslte_vec_u8_malloc(1024 * 1024 * 8); + int8_t* llr = srslte_vec_i8_malloc(1024 * 1024 * 8); + uint8_t* data_rx = srslte_vec_u8_malloc(1024 * 1024); + + // Set default PDSCH configuration + pdsch_cfg.mcs_table = srslte_mcs_table_256qam; + pdsch_cfg.serving_cell_cfg.max_mimo_layers = 2; + + if (parse_args(argc, argv) < SRSLTE_SUCCESS) { + goto clean_exit; + } + + if (data_tx == NULL || data_rx == NULL) { + goto clean_exit; + } + + if (srslte_sch_nr_init_tx(&sch_nr_tx) < SRSLTE_SUCCESS) { + ERROR("Error initiating SCH NR for Tx\n"); + goto clean_exit; + } + + srslte_sch_nr_decoder_cfg_t decoder_cfg = {}; + decoder_cfg.disable_simd = true; + if (srslte_sch_nr_init_rx(&sch_nr_rx, &decoder_cfg) < SRSLTE_SUCCESS) { + ERROR("Error initiating SCH NR for Rx\n"); + goto clean_exit; + } + + if (srslte_sch_nr_set_carrier(&sch_nr_tx, &carrier)) { + ERROR("Error setting SCH NR carrier\n"); + goto clean_exit; + } + + if (srslte_sch_nr_set_carrier(&sch_nr_rx, &carrier)) { + ERROR("Error setting SCH NR carrier\n"); + goto clean_exit; + } + + srslte_softbuffer_tx_t softbuffer_tx = {}; + srslte_softbuffer_rx_t softbuffer_rx = {}; + + if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, 50, 18000) < SRSLTE_SUCCESS) { + ERROR("Error init soft-buffer\n"); + goto clean_exit; + } + + if (srslte_softbuffer_rx_init_guru(&softbuffer_rx, 50, 18000) < SRSLTE_SUCCESS) { + ERROR("Error init soft-buffer\n"); + goto clean_exit; + } + + // Use grant default A time resources with m=0 + if (srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg_typeA.typeA_pos, &pdsch_grant) < + SRSLTE_SUCCESS) { + ERROR("Error loading default grant\n"); + goto clean_exit; + } + pdsch_grant.nof_layers = pdsch_cfg.serving_cell_cfg.max_mimo_layers; + pdsch_grant.dci_format = srslte_dci_format_nr_1_0; + + uint32_t n_prb_start = 1; + uint32_t n_prb_end = carrier.nof_prb + 1; + if (n_prb > 0) { + n_prb_start = SRSLTE_MIN(n_prb, n_prb_end - 1); + n_prb_end = SRSLTE_MIN(n_prb + 1, n_prb_end); + } + + uint32_t mcs_start = 0; + uint32_t mcs_end = pdsch_cfg.mcs_table == srslte_mcs_table_256qam ? 28 : 29; + if (mcs < mcs_end) { + mcs_start = SRSLTE_MIN(mcs, mcs_end - 1); + mcs_end = SRSLTE_MIN(mcs + 1, mcs_end); + } + + for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { + for (mcs = mcs_start; mcs < mcs_end; mcs++) { + + for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { + pdsch_grant.prb_idx[n] = (n < n_prb); + } + + srslte_ra_tb_nr_t tb = {}; + if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &tb) < SRSLTE_SUCCESS) { + ERROR("Error filing tb\n"); + goto clean_exit; + } + + for (uint32_t i = 0; i < tb.tbs; i++) { + data_tx[i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); + } + + tb.softbuffer.tx = &softbuffer_tx; + + if (srslte_dlsch_nr_encode(&sch_nr_tx, &pdsch_cfg, &tb, data_tx, encoded) < SRSLTE_SUCCESS) { + ERROR("Error encoding\n"); + goto clean_exit; + } + + for (uint32_t i = 0; i < tb.nof_bits; i++) { + llr[i] = encoded[i] ? -10 : +10; + } + + tb.softbuffer.rx = &softbuffer_rx; + srslte_softbuffer_rx_reset(tb.softbuffer.rx); + + bool crc = false; + if (srslte_dlsch_nr_decode(&sch_nr_rx, &pdsch_cfg, &tb, llr, data_rx, &crc) < SRSLTE_SUCCESS) { + ERROR("Error encoding\n"); + goto clean_exit; + } + + if (!crc) { + ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, tb.tbs); + goto clean_exit; + } + + if (memcmp(data_tx, data_rx, tb.tbs / 8) != 0) { + ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, tb.tbs); + printf("Tx data: "); + srslte_vec_fprint_byte(stdout, data_tx, tb.tbs / 8); + printf("Rx data: "); + srslte_vec_fprint_byte(stdout, data_rx, tb.tbs / 8); + goto clean_exit; + } + + printf("n_prb=%d; mcs=%d; TBS=%d; PASSED!\n", n_prb, mcs, tb.tbs); + } + } + + ret = SRSLTE_SUCCESS; + +clean_exit: + srslte_random_free(rand_gen); + srslte_sch_nr_free(&sch_nr_tx); + srslte_sch_nr_free(&sch_nr_rx); + if (data_tx) { + free(data_tx); + } + if (data_rx) { + free(data_rx); + } + if (llr) { + free(llr); + } + if (encoded) { + free(encoded); + } + srslte_softbuffer_tx_free(&softbuffer_tx); + srslte_softbuffer_rx_free(&softbuffer_rx); + + return SRSLTE_SUCCESS; +} \ No newline at end of file