diff --git a/lib/include/srslte/phy/phch/dci_nr.h b/lib/include/srslte/phy/phch/dci_nr.h index 845aec18c..535828284 100644 --- a/lib/include/srslte/phy/phch/dci_nr.h +++ b/lib/include/srslte/phy/phch/dci_nr.h @@ -28,7 +28,7 @@ typedef enum SRSLTE_API { typedef struct SRSLTE_API { srslte_dci_location_t location; srslte_search_space_type_t search_space; - uint8_t payload[32]; + uint8_t payload[50]; srslte_rnti_type_t rnti_type; uint32_t nof_bits; srslte_dci_format_nr_t format; diff --git a/lib/include/srslte/phy/phch/pdcch_nr.h b/lib/include/srslte/phy/phch/pdcch_nr.h index 657aa7f08..39bbeb6b5 100644 --- a/lib/include/srslte/phy/phch/pdcch_nr.h +++ b/lib/include/srslte/phy/phch/pdcch_nr.h @@ -37,6 +37,7 @@ typedef struct { bool disable_simd; bool measure_evm; + bool measure_time; } srslte_pdcch_nr_args_t; /** @@ -51,12 +52,18 @@ typedef struct SRSLTE_API { srslte_carrier_nr_t carrier; srslte_coreset_t coreset; srslte_crc_t crc24c; - uint8_t* c; // Message bits with attached CRC - uint8_t* d; // encoded bits - uint8_t* f; // bits at the Rate matching output + uint8_t* c; // Message bits with attached CRC + uint8_t* d; // encoded bits + uint8_t* f; // bits at the Rate matching output + uint8_t* allocated; // Allocated polar bit buffer, encoder input, decoder output cf_t* symbols; srslte_modem_table_t modem_table; srslte_evm_buffer_t* evm_buffer; + bool meas_time_en; + uint32_t meas_time_us; + uint32_t K; + uint32_t M; + uint32_t E; } srslte_pdcch_nr_t; /** @@ -92,7 +99,7 @@ SRSLTE_API int srslte_pdcch_nr_init_tx(srslte_pdcch_nr_t* q, const srslte_pdcch_ SRSLTE_API int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args); -SRSLTE_API void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q); +SRSLTE_API void srslte_pdcch_nr_free(srslte_pdcch_nr_t* q); SRSLTE_API int srslte_pdcch_nr_set_carrier(srslte_pdcch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset); @@ -116,4 +123,18 @@ SRSLTE_API int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, srslte_dci_msg_nr_t* dci_msg, srslte_pdcch_nr_res_t* res); +/** + * @brief Stringifies NR PDCCH decoding information from the latest encoded/decoded transmission + * + * @param[in] q provides PDCCH encoder/decoder object + * @param[in] res Optional PDCCH decode result + * @param[out] str Destination string + * @param[out] str_len Maximum destination string length + * @return The number of characters written in the string + */ +SRSLTE_API uint32_t srslte_pdcch_nr_info(const srslte_pdcch_nr_t* q, + const srslte_pdcch_nr_res_t* res, + char* str, + uint32_t str_len); + #endif // SRSLTE_PDCCH_NR_H diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index 5808c1718..9eafd5abd 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -11,9 +11,12 @@ */ #include "srslte/phy/phch/pdcch_nr.h" +#include "srslte/phy/fec/polar/polar_chanalloc.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" +#define PDCCH_NR_POLAR_RM_IBIL 0 + /** * @brief Recursive Y_p_n function */ @@ -107,6 +110,8 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args return SRSLTE_ERROR_INVALID_INPUTS; } + q->meas_time_en = args->measure_time; + q->c = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2); if (q->c == NULL) { return SRSLTE_ERROR; @@ -127,6 +132,11 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args return SRSLTE_ERROR; } + q->allocated = srslte_vec_u8_malloc(NMAX); + if (q->allocated == NULL) { + return SRSLTE_ERROR; + } + if (srslte_crc_init(&q->crc24c, SRSLTE_LTE_CRC24C, 24) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } @@ -136,6 +146,9 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args } srslte_modem_table_lte(&q->modem_table, SRSLTE_MOD_QPSK); + if (args->measure_evm) { + srslte_modem_table_bytes(&q->modem_table); + } return SRSLTE_SUCCESS; } @@ -185,7 +198,7 @@ int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* return SRSLTE_SUCCESS; } -void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q) +void srslte_pdcch_nr_free(srslte_pdcch_nr_t* q) { if (q == NULL) { return; @@ -213,8 +226,20 @@ void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q) free(q->f); } + if (q->allocated) { + free(q->allocated); + } + + if (q->symbols) { + free(q->symbols); + } + srslte_modem_table_free(&q->modem_table); + if (q->evm_buffer) { + srslte_evm_free(q->evm_buffer); + } + SRSLTE_MEM_ZERO(q, srslte_pdcch_nr_t, 1); } @@ -291,15 +316,21 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ return SRSLTE_ERROR; } + struct timeval t[3]; + if (q->meas_time_en) { + gettimeofday(&t[1], NULL); + } + // Calculate... - uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC - uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE - uint32_t E = M * 2; // Number of Rate-Matched bits + q->K = dci_msg->nof_bits + 24U; // Payload size including CRC + q->M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE + q->E = q->M * 2; // Number of Rate-Matched bits // Get polar code - if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) { + if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + INFO("PDCCH NR TX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); // Copy DCI message srslte_vec_u8_copy(q->c, dci_msg->payload, dci_msg->nof_bits); @@ -307,35 +338,64 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ // Append CRC srslte_crc_attach(&q->crc24c, q->c, dci_msg->nof_bits); + INFO("PDCCH NR TX: Append CRC %06x\n", (uint32_t)srslte_crc_checksum_get(&q->crc24c)); + // Unpack RNTI uint8_t unpacked_rnti[16] = {}; uint8_t* ptr = unpacked_rnti; srslte_bit_unpack(dci_msg->rnti, &ptr, 16); // Scramble CRC with RNTI - srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16); + srslte_vec_xor_bbb(unpacked_rnti, &q->c[q->K - 16], &q->c[q->K - 16], 16); + + // Print c + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + INFO("PDCCH NR TX: c="); + srslte_vec_fprint_hex(stdout, q->c, q->K); + } + + // Allocate channel + srslte_polar_chanalloc_tx(q->c, q->allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); // Encode bits - if (srslte_polar_encoder_encode(&q->encoder, q->c, q->d, q->code.n) < SRSLTE_SUCCESS) { + if (srslte_polar_encoder_encode(&q->encoder, q->allocated, q->d, q->code.n) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + // Print d + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + INFO("PDCCH NR TX: d="); + srslte_vec_fprint_byte(stdout, q->d, q->K); + } + // Rate matching - srslte_polar_rm_tx(&q->rm, q->d, q->f, q->code.n, E, K, 0); + srslte_polar_rm_tx(&q->rm, q->d, q->f, q->code.n, q->E, q->K, PDCCH_NR_POLAR_RM_IBIL); // Scrambling - srslte_sequence_apply_bit(q->f, q->f, E, pdcch_nr_c_init(q, dci_msg)); + srslte_sequence_apply_bit(q->f, q->f, q->E, pdcch_nr_c_init(q, dci_msg)); // Modulation - srslte_mod_modulate(&q->modem_table, q->f, q->symbols, E); + srslte_mod_modulate(&q->modem_table, q->f, q->symbols, q->E); // Put symbols in grid uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true); - if (M != m) { - ERROR("Unmatch number of RE (%d != %d)\n", m, M); + if (q->M != m) { + ERROR("Unmatch number of RE (%d != %d)\n", m, q->M); return SRSLTE_ERROR; } + if (q->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->meas_time_us = (uint32_t)t[0].tv_usec; + } + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + char str[128] = {}; + srslte_pdcch_nr_info(q, NULL, str, sizeof(str)); + INFO("PDCCH NR TX: %s\n", str); + } + return SRSLTE_SUCCESS; } @@ -349,73 +409,139 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, return SRSLTE_ERROR; } + struct timeval t[3]; + if (q->meas_time_en) { + gettimeofday(&t[1], NULL); + } + // Calculate... - uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC - uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE - uint32_t E = M * 2; // Number of Rate-Matched bits + q->K = dci_msg->nof_bits + 24U; // Payload size including CRC + q->M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE + q->E = q->M * 2; // Number of Rate-Matched bits // Check number of estimates is correct - if (ce->nof_re != M) { - ERROR("Invalid number of channel estimates (%d != %d)\n", M, ce->nof_re); + if (ce->nof_re != q->M) { + ERROR("Invalid number of channel estimates (%d != %d)\n", q->M, ce->nof_re); return SRSLTE_ERROR; } // Get polar code - if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) { + if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + INFO("PDCCH NR RX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); // Get symbols from grid uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false); - if (M != m) { - ERROR("Unmatch number of RE (%d != %d)\n", m, M); + if (q->M != m) { + ERROR("Unmatch number of RE (%d != %d)\n", m, q->M); + return SRSLTE_ERROR; } // Equalise - srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, M, 1.0f, ce->noise_var); + srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, q->M, 1.0f, ce->noise_var); // Demodulation int8_t* llr = (int8_t*)q->f; - srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, M); + srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, q->M); // Measure EVM if configured if (q->evm_buffer != NULL) { - res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_table, q->symbols, llr, E); + res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_table, q->symbols, llr, q->E); } else { res->evm = NAN; } + // Negate all LLR + for (uint32_t i = 0; i < q->E; i++) { + llr[i] *= -1; + } + // Descrambling - srslte_sequence_apply_c(llr, llr, E, pdcch_nr_c_init(q, dci_msg)); + srslte_sequence_apply_c(llr, llr, q->E, pdcch_nr_c_init(q, dci_msg)); // Un-rate matching int8_t* d = (int8_t*)q->d; - if (srslte_polar_rm_rx_c(&q->rm, llr, d, E, q->code.n, K, 0) < SRSLTE_SUCCESS) { + if (srslte_polar_rm_rx_c(&q->rm, llr, d, q->E, q->code.n, q->K, PDCCH_NR_POLAR_RM_IBIL) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + // Print d + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + INFO("PDCCH NR RX: d="); + srslte_vec_fprint_bs(stdout, d, q->K); + } + // Decode - if (srslte_polar_decoder_decode_c(&q->decoder, d, q->c, q->code.n, q->code.F_set, q->code.F_set_size) < + if (srslte_polar_decoder_decode_c(&q->decoder, d, q->allocated, q->code.n, q->code.F_set, q->code.F_set_size) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } + // De-allocate channel + srslte_polar_chanalloc_rx(q->allocated, q->c, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); + + // Print c + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + INFO("PDCCH NR RX: c="); + srslte_vec_fprint_hex(stdout, q->c, q->K); + } + // Unpack RNTI uint8_t unpacked_rnti[16] = {}; uint8_t* ptr = unpacked_rnti; srslte_bit_unpack(dci_msg->rnti, &ptr, 16); // De-Scramble CRC with RNTI - ptr = &q->c[K - 24]; - srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16); + ptr = &q->c[q->K - 24]; + srslte_vec_xor_bbb(unpacked_rnti, &q->c[q->K - 16], &q->c[q->K - 16], 16); // Check CRC uint32_t checksum1 = srslte_crc_checksum(&q->crc24c, q->c, dci_msg->nof_bits); uint32_t checksum2 = srslte_bit_pack(&ptr, 24); res->crc = checksum1 == checksum2; + INFO("PDCCH NR RX: CRC={%06x, %06x}\n", checksum1, checksum2); + // Copy DCI message srslte_vec_u8_copy(dci_msg->payload, q->c, dci_msg->nof_bits); + if (q->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->meas_time_us = (uint32_t)t[0].tv_usec; + } + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + char str[128] = {}; + srslte_pdcch_nr_info(q, res, str, sizeof(str)); + INFO("PDCCH NR RX: %s\n", str); + } + return SRSLTE_SUCCESS; +} + +uint32_t srslte_pdcch_nr_info(const srslte_pdcch_nr_t* q, const srslte_pdcch_nr_res_t* res, char* str, uint32_t str_len) +{ + int len = 0; + + if (q == NULL) { + return len; + } + + len = srslte_print_check(str, str_len, len, "K=%d,E=%d", q->K, q->E); + + if (res != NULL) { + len = srslte_print_check(str, str_len, len, ",crc=%s", res->crc ? "OK" : "KO"); + + if (q->evm_buffer && res) { + len = srslte_print_check(str, str_len, len, ",evm=%.2f", res->evm); + } + } + + if (q->meas_time_en) { + len = srslte_print_check(str, str_len, len, ",t=%d us", q->meas_time_us); + } + + return len; } \ No newline at end of file diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index cc9d2ab10..d19dd3608 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -621,3 +621,8 @@ add_test(dlsch_nr_test dlsch_nr_test -m 0 -p 1) add_executable(pdsch_nr_test pdsch_nr_test.c) target_link_libraries(pdsch_nr_test srslte_phy) add_test(pdsch_nr_test pdsch_nr_test -p 6 -m 20) + + +add_executable(pdcch_nr_test pdcch_nr_test.c) +target_link_libraries(pdcch_nr_test srslte_phy) +add_test(pdcch_nr_test pdcch_nr_test) diff --git a/lib/src/phy/phch/test/pdcch_nr_test.c b/lib/src/phy/phch/test/pdcch_nr_test.c new file mode 100644 index 000000000..9deb9320c --- /dev/null +++ b/lib/src/phy/phch/test/pdcch_nr_test.c @@ -0,0 +1,265 @@ +/* + * 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/common/test_common.h" +#include "srslte/phy/phch/pdcch_nr.h" +#include + +static srslte_carrier_nr_t carrier = { + 0, // cell_id + 0, // numerology + SRSLTE_MAX_PRB_NR, // nof_prb + 0 // start +}; + +static uint16_t rnti = 0x1234; + +typedef struct { + uint64_t time_us; + uint64_t count; +} proc_time_t; + +static proc_time_t enc_time[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR] = {}; +static proc_time_t dec_time[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR] = {}; + +static int test(srslte_pdcch_nr_t* tx, + srslte_pdcch_nr_t* rx, + cf_t* grid, + srslte_dmrs_pdcch_ce_t* ce, + srslte_dci_msg_nr_t* dci_msg_tx) +{ + // Encode PDCCH + TESTASSERT(srslte_pdcch_nr_encode(tx, dci_msg_tx, grid) == SRSLTE_SUCCESS); + + enc_time[dci_msg_tx->location.L].time_us += tx->meas_time_us; + enc_time[dci_msg_tx->location.L].count++; + + // Init Rx MSG + srslte_pdcch_nr_res_t res = {}; + srslte_dci_msg_nr_t dci_msg_rx = *dci_msg_tx; + srslte_vec_u8_zero(dci_msg_rx.payload, dci_msg_rx.nof_bits); + + // Decode PDCCH + TESTASSERT(srslte_pdcch_nr_decode(rx, grid, ce, &dci_msg_rx, &res) == SRSLTE_SUCCESS); + + dec_time[dci_msg_tx->location.L].time_us += rx->meas_time_us; + dec_time[dci_msg_tx->location.L].count++; + + // Assert + TESTASSERT(res.evm < 0.01f); + TESTASSERT(res.crc); + + return SRSLTE_SUCCESS; +} + +static void usage(char* prog) +{ + printf("Usage: %s [v] \n", prog); + printf("\t-p Number of carrier PRB [Default %d]\n", carrier.nof_prb); + // printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); + // printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", + // srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table)); + // printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.sch_cfg.max_mimo_layers); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +static int parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "vp")) != -1) { + switch (opt) { + case 'p': + carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + return SRSLTE_ERROR; + } + } + + return SRSLTE_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSLTE_ERROR; + + srslte_pdcch_nr_args_t args = {}; + args.disable_simd = false; + args.measure_evm = true; + args.measure_time = true; + + srslte_pdcch_nr_t pdcch_tx = {}; + srslte_pdcch_nr_t pdcch_rx = {}; + + if (parse_args(argc, argv) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + uint32_t grid_sz = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR; + srslte_random_t rand_gen = srslte_random_init(1234); + srslte_dmrs_pdcch_ce_t* ce = SRSLTE_MEM_ALLOC(srslte_dmrs_pdcch_ce_t, 1); + cf_t* buffer = srslte_vec_cf_malloc(grid_sz); + if (rand_gen == NULL || ce == NULL || buffer == NULL) { + ERROR("Error malloc\n"); + goto clean_exit; + } + + SRSLTE_MEM_ZERO(ce, srslte_dmrs_pdcch_ce_t, 1); + + if (srslte_pdcch_nr_init_tx(&pdcch_tx, &args) < SRSLTE_SUCCESS) { + ERROR("Error init\n"); + goto clean_exit; + } + + if (srslte_pdcch_nr_init_rx(&pdcch_rx, &args) < SRSLTE_SUCCESS) { + ERROR("Error init\n"); + goto clean_exit; + } + + srslte_coreset_t coreset = {}; + uint32_t nof_frequency_resource = SRSLTE_MIN(SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE, carrier.nof_prb / 6); + for (uint32_t frequency_resources = 1; frequency_resources < (1U << nof_frequency_resource); frequency_resources++) { + for (uint32_t i = 0; i < nof_frequency_resource; i++) { + uint32_t mask = ((frequency_resources >> i) & 1U); + coreset.freq_resources[i] = (mask == 1); + } + for (coreset.duration = SRSLTE_CORESET_DURATION_MIN; coreset.duration <= SRSLTE_CORESET_DURATION_MAX; + coreset.duration++) { + + srslte_search_space_t search_space = {}; + search_space.type = srslte_search_space_type_ue; + + if (srslte_pdcch_nr_set_carrier(&pdcch_tx, &carrier, &coreset) < SRSLTE_SUCCESS) { + ERROR("Error setting carrier\n"); + goto clean_exit; + } + + if (srslte_pdcch_nr_set_carrier(&pdcch_rx, &carrier, &coreset) < SRSLTE_SUCCESS) { + ERROR("Error setting carrier\n"); + goto clean_exit; + } + + uint32_t coreset_bw = srslte_coreset_get_bw(&coreset); + uint32_t nof_cce = (coreset_bw * coreset.duration) / 6; + uint32_t max_aggregation_level = (uint32_t)floor(log2(nof_cce)); + max_aggregation_level = SRSLTE_MIN(max_aggregation_level + 1, SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR); + + // Fill search space maximum number of candidates + for (uint32_t aggregation_level = 0; aggregation_level < max_aggregation_level; aggregation_level++) { + uint32_t L = 1U << aggregation_level; + uint32_t nof_candidates = nof_cce / L; + nof_candidates = SRSLTE_MIN(nof_candidates, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); + search_space.nof_candidates[aggregation_level] = nof_candidates; + } + for (uint32_t aggregation_level = max_aggregation_level; + aggregation_level < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; + aggregation_level++) { + search_space.nof_candidates[aggregation_level] = 0; + } + + for (uint32_t aggregation_level = 0; aggregation_level < max_aggregation_level; aggregation_level++) { + uint32_t L = 1U << aggregation_level; + + for (uint32_t slot_idx = 0; slot_idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_idx++) { + uint32_t dci_locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; + + // Calculate candidate locations + int n = srslte_pdcch_nr_locations_coreset( + &coreset, &search_space, rnti, aggregation_level, slot_idx, dci_locations); + if (n < SRSLTE_SUCCESS) { + ERROR("Error calculating locations in CORESET\n"); + goto clean_exit; + } + if (n == 0) { + ERROR("Invalid number of locations (%d)\n", n); + goto clean_exit; + } + + for (uint32_t ncce_idx = 0; ncce_idx < n; ncce_idx++) { + + // Init MSG + srslte_dci_msg_nr_t dci_msg = {}; + dci_msg.rnti_type = srslte_rnti_type_c; + dci_msg.location.L = aggregation_level; + dci_msg.location.ncce = dci_locations[n]; + dci_msg.nof_bits = srslte_dci_nr_format_1_0_sizeof(&carrier, &coreset, dci_msg.rnti_type); + + // Generate random payload + for (uint32_t i = 0; i < dci_msg.nof_bits; i++) { + dci_msg.payload[i] = srslte_random_uniform_int_dist(rand_gen, 0, 1); + } + + // Set channel estimate number of elements and set out-of-range values to zero + ce->nof_re = (SRSLTE_NRE - 3) * 6 * L; + for (uint32_t i = 0; i < SRSLTE_PDCCH_MAX_RE; i++) { + ce->ce[i] = (i < ce->nof_re) ? 1.0f : 0.0f; + } + ce->noise_var = 0.0f; + + if (test(&pdcch_tx, &pdcch_rx, buffer, ce, &dci_msg) < SRSLTE_SUCCESS) { + ERROR("test failed\n"); + goto clean_exit; + } + } + } + } + } + } + + printf("%6s %6s %6s\n", " ", " Time ", " Time "); + printf("%6s %6s %6s\n", "L", "Encode", "Decode"); + printf("%6s %6s %6s\n", " ", " (us) ", " (us) "); + for (uint32_t i = 0; i < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; i++) { + if (enc_time[i].count > 0 && dec_time[i].count) { + printf("%6d %6.1f %6.1f\n", + i, + (double)enc_time[i].time_us / (double)enc_time[i].count, + (double)dec_time[i].time_us / (double)dec_time[i].count); + } + } + + ret = SRSLTE_SUCCESS; +clean_exit: + srslte_random_free(rand_gen); + + if (ce) { + free(ce); + } + + if (buffer) { + free(buffer); + } + + srslte_pdcch_nr_free(&pdcch_tx); + srslte_pdcch_nr_free(&pdcch_rx); + + if (ret == SRSLTE_SUCCESS) { + printf("Passed!\n"); + } else { + printf("Failed!\n"); + } + + return ret; +} \ No newline at end of file