diff --git a/lib/include/srslte/phy/enb/enb_dl_nr.h b/lib/include/srslte/phy/enb/enb_dl_nr.h new file mode 100644 index 000000000..e3f9b23ae --- /dev/null +++ b/lib/include/srslte/phy/enb/enb_dl_nr.h @@ -0,0 +1,62 @@ +/* + * 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/. + * + */ + +#ifndef SRSLTE_ENB_DL_NR_H +#define SRSLTE_ENB_DL_NR_H + +#include "srslte/phy/common/phy_common_nr.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/phch/pdsch_nr.h" + +typedef struct SRSLTE_API { + srslte_pdsch_args_t pdsch; + uint32_t nof_tx_antennas; +} srslte_enb_dl_nr_args_t; + +typedef struct SRSLTE_API { + uint32_t max_prb; + uint32_t nof_tx_antennas; + srslte_carrier_nr_t carrier; + + srslte_ofdm_t fft[SRSLTE_MAX_PORTS]; + + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + srslte_pdsch_nr_t pdsch; + srslte_dmrs_pdsch_t dmrs; +} srslte_enb_dl_nr_t; + +SRSLTE_API int +srslte_enb_dl_nr_init(srslte_enb_dl_nr_t* q, cf_t* output[SRSLTE_MAX_PORTS], const srslte_enb_dl_nr_args_t* args); + +SRSLTE_API int +srslte_enb_dl_nr_set_carrier(srslte_enb_dl_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_t* common); + +SRSLTE_API void srslte_enb_dl_nr_free(srslte_enb_dl_nr_t* q); + +SRSLTE_API void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q); + +SRSLTE_API int srslte_enb_dl_nr_pdsch_put(srslte_enb_dl_nr_t* q, + const srslte_dl_slot_cfg_t* slot, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + uint8_t* data[SRSLTE_MAX_TB]); + +#endif // SRSLTE_ENB_DL_NR_H diff --git a/lib/include/srslte/phy/phch/pdsch_nr.h b/lib/include/srslte/phy/phch/pdsch_nr.h index 8218b252b..49332eb9a 100644 --- a/lib/include/srslte/phy/phch/pdsch_nr.h +++ b/lib/include/srslte/phy/phch/pdsch_nr.h @@ -70,9 +70,9 @@ typedef struct { float evm; } srslte_pdsch_res_nr_t; -SRSLTE_API int srslte_pdsch_nr_init_tx(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args); +SRSLTE_API int srslte_pdsch_nr_init_enb(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args); -SRSLTE_API int srslte_pdsch_nr_init_rx(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args); +SRSLTE_API int srslte_pdsch_nr_init_ue(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args); SRSLTE_API void srslte_pdsch_nr_free(srslte_pdsch_nr_t* q); diff --git a/lib/include/srslte/phy/ue/ue_dl_nr.h b/lib/include/srslte/phy/ue/ue_dl_nr.h new file mode 100644 index 000000000..f2fd92f12 --- /dev/null +++ b/lib/include/srslte/phy/ue/ue_dl_nr.h @@ -0,0 +1,63 @@ +/* + * 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/. + * + */ + +#ifndef SRSLTE_UE_DL_NR_H +#define SRSLTE_UE_DL_NR_H + +#include "srslte/phy/common/phy_common_nr.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/phch/pdsch_nr.h" + +typedef struct SRSLTE_API { + srslte_pdsch_args_t pdsch; + uint32_t nof_rx_antennas; +} srslte_ue_dl_nr_args_t; + +typedef struct SRSLTE_API { + uint32_t max_prb; + uint32_t nof_rx_antennas; + srslte_carrier_nr_t carrier; + + srslte_ofdm_t fft[SRSLTE_MAX_PORTS]; + + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + srslte_chest_dl_res_t chest; + srslte_pdsch_nr_t pdsch; + srslte_dmrs_pdsch_t dmrs; +} srslte_ue_dl_nr_t; + +SRSLTE_API int +srslte_ue_dl_nr_init(srslte_ue_dl_nr_t* q, cf_t* input[SRSLTE_MAX_PORTS], const srslte_ue_dl_nr_args_t* args); + +SRSLTE_API int +srslte_ue_dl_nr_set_carrier(srslte_ue_dl_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_t* common); + +SRSLTE_API void srslte_ue_dl_nr_free(srslte_ue_dl_nr_t* q); + +SRSLTE_API void srslte_ue_dl_nr_estimate_fft(srslte_ue_dl_nr_t* q); + +SRSLTE_API int srslte_ue_dl_nr_pdsch_get(srslte_ue_dl_nr_t* q, + const srslte_dl_slot_cfg_t* slot, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + srslte_pdsch_res_nr_t* res); + +#endif // SRSLTE_UE_DL_NR_H diff --git a/lib/src/phy/enb/enb_dl_nr.c b/lib/src/phy/enb/enb_dl_nr.c new file mode 100644 index 000000000..e88298ab6 --- /dev/null +++ b/lib/src/phy/enb/enb_dl_nr.c @@ -0,0 +1,160 @@ +/* + * 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/enb/enb_dl_nr.h" + +static int enb_dl_alloc_prb(srslte_enb_dl_nr_t* q, uint32_t new_nof_prb) +{ + if (q->max_prb < new_nof_prb) { + q->max_prb = new_nof_prb; + + for (uint32_t i = 0; i < q->nof_tx_antennas; i++) { + if (q->sf_symbols[i] != NULL) { + free(q->sf_symbols[i]); + } + + q->sf_symbols[i] = srslte_vec_cf_malloc(SRSLTE_SLOT_LEN_RE_NR(q->max_prb)); + if (q->sf_symbols[i] == NULL) { + ERROR("Malloc\n"); + return SRSLTE_ERROR; + } + } + } + + return SRSLTE_SUCCESS; +} + +int srslte_enb_dl_nr_init(srslte_enb_dl_nr_t* q, cf_t* output[SRSLTE_MAX_PORTS], const srslte_enb_dl_nr_args_t* args) +{ + if (!q || !output || !args) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (args->nof_tx_antennas == 0) { + ERROR("Error invalid number of antennas (%d)\n", args->nof_tx_antennas); + return SRSLTE_ERROR; + } + + q->nof_tx_antennas = args->nof_tx_antennas; + + if (srslte_pdsch_nr_init_enb(&q->pdsch, &args->pdsch) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (enb_dl_alloc_prb(q, SRSLTE_MAX_PRB_NR) < SRSLTE_SUCCESS) { + ERROR("Error allocating\n"); + return SRSLTE_ERROR; + } + + srslte_ofdm_cfg_t fft_cfg = {}; + fft_cfg.nof_prb = 100; + fft_cfg.symbol_sz = srslte_symbol_sz(100); + fft_cfg.keep_dc = true; + + for (uint32_t i = 0; i < q->nof_tx_antennas; i++) { + fft_cfg.in_buffer = q->sf_symbols[i]; + fft_cfg.out_buffer = output[i]; + srslte_ofdm_tx_init_cfg(&q->fft[i], &fft_cfg); + } + + if (srslte_dmrs_pdsch_init(&q->dmrs, false) < SRSLTE_SUCCESS) { + ERROR("Error DMRS\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +void srslte_enb_dl_nr_free(srslte_enb_dl_nr_t* q) +{ + if (q == NULL) { + return; + } + + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + srslte_ofdm_rx_free(&q->fft[i]); + + if (q->sf_symbols[i] != NULL) { + free(q->sf_symbols[i]); + } + } + + srslte_pdsch_nr_free(&q->pdsch); + srslte_dmrs_pdsch_free(&q->dmrs); + + memset(q, 0, sizeof(srslte_enb_dl_nr_t)); +} + +int srslte_enb_dl_nr_set_carrier(srslte_enb_dl_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_t* sch) +{ + if (srslte_pdsch_nr_set_carrier(&q->pdsch, carrier, sch) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (srslte_dmrs_pdsch_set_carrier(&q->dmrs, carrier) < SRSLTE_SUCCESS) { + ERROR("Error DMRS\n"); + return SRSLTE_ERROR; + } + + if (enb_dl_alloc_prb(q, carrier->nof_prb) < SRSLTE_SUCCESS) { + ERROR("Error allocating\n"); + return SRSLTE_ERROR; + } + + if (carrier->nof_prb != q->carrier.nof_prb) { + for (uint32_t i = 0; i < q->nof_tx_antennas; i++) { + srslte_ofdm_tx_set_prb(&q->fft[i], SRSLTE_CP_NORM, carrier->nof_prb); + } + } + + q->carrier = *carrier; + + return SRSLTE_SUCCESS; +} + +void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q) +{ + if (q == NULL) { + return; + } + + for (uint32_t i = 0; i < q->nof_tx_antennas; i++) { + srslte_ofdm_tx_sf(&q->fft[i]); + } +} + +int srslte_enb_dl_nr_pdsch_put(srslte_enb_dl_nr_t* q, + const srslte_dl_slot_cfg_t* slot, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + uint8_t* data[SRSLTE_MAX_TB]) +{ + + if (srslte_dmrs_pdsch_put_sf(&q->dmrs, slot, cfg, grant, q->sf_symbols[0]) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (srslte_pdsch_nr_encode(&q->pdsch, cfg, grant, data, q->sf_symbols) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index 5ce77313e..2a897e869 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -37,7 +37,7 @@ int pdsch_nr_init_common(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args) return SRSLTE_SUCCESS; } -int srslte_pdsch_nr_init_tx(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args) +int srslte_pdsch_nr_init_enb(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args) { if (q == NULL) { @@ -56,7 +56,7 @@ int srslte_pdsch_nr_init_tx(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* arg return SRSLTE_SUCCESS; } -int srslte_pdsch_nr_init_rx(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args) +int srslte_pdsch_nr_init_ue(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* args) { if (q == NULL || args == NULL) { diff --git a/lib/src/phy/phch/test/pdsch_nr_test.c b/lib/src/phy/phch/test/pdsch_nr_test.c index 1ad301459..ef1d7e4f1 100644 --- a/lib/src/phy/phch/test/pdsch_nr_test.c +++ b/lib/src/phy/phch/test/pdsch_nr_test.c @@ -103,12 +103,12 @@ int main(int argc, char** argv) pdsch_args.sch.disable_simd = true; pdsch_args.measure_evm = true; - if (srslte_pdsch_nr_init_tx(&pdsch_tx, &pdsch_args) < SRSLTE_SUCCESS) { + if (srslte_pdsch_nr_init_enb(&pdsch_tx, &pdsch_args) < SRSLTE_SUCCESS) { ERROR("Error initiating PDSCH for Tx\n"); goto clean_exit; } - if (srslte_pdsch_nr_init_rx(&pdsch_rx, &pdsch_args) < SRSLTE_SUCCESS) { + if (srslte_pdsch_nr_init_ue(&pdsch_rx, &pdsch_args) < SRSLTE_SUCCESS) { ERROR("Error initiating SCH NR for Rx\n"); goto clean_exit; } diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c new file mode 100644 index 000000000..b1ec2de38 --- /dev/null +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -0,0 +1,175 @@ +/* + * 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/ue/ue_dl_nr.h" + +static int ue_dl_alloc_prb(srslte_ue_dl_nr_t* q, uint32_t new_nof_prb) +{ + if (q->max_prb < new_nof_prb) { + q->max_prb = new_nof_prb; + + srslte_chest_dl_res_free(&q->chest); + if (srslte_chest_dl_res_init(&q->chest, q->max_prb) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + if (q->sf_symbols[i] != NULL) { + free(q->sf_symbols[i]); + } + + q->sf_symbols[i] = srslte_vec_cf_malloc(SRSLTE_SLOT_LEN_RE_NR(q->max_prb)); + if (q->sf_symbols[i] == NULL) { + ERROR("Malloc\n"); + return SRSLTE_ERROR; + } + } + } + + return SRSLTE_SUCCESS; +} + +int srslte_ue_dl_nr_init(srslte_ue_dl_nr_t* q, cf_t* input[SRSLTE_MAX_PORTS], const srslte_ue_dl_nr_args_t* args) +{ + if (!q || !input || !args) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (args->nof_rx_antennas == 0) { + ERROR("Error invalid number of antennas (%d)\n", args->nof_rx_antennas); + return SRSLTE_ERROR; + } + + q->nof_rx_antennas = args->nof_rx_antennas; + + if (srslte_pdsch_nr_init_ue(&q->pdsch, &args->pdsch) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (ue_dl_alloc_prb(q, SRSLTE_MAX_PRB_NR)) { + ERROR("Error allocating\n"); + return SRSLTE_ERROR; + } + + srslte_ofdm_cfg_t fft_cfg = {}; + fft_cfg.nof_prb = 100; + fft_cfg.symbol_sz = srslte_symbol_sz(100); + fft_cfg.keep_dc = true; + + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + fft_cfg.in_buffer = input[i]; + fft_cfg.out_buffer = q->sf_symbols[i]; + srslte_ofdm_rx_init_cfg(&q->fft[i], &fft_cfg); + } + + if (srslte_dmrs_pdsch_init(&q->dmrs, true) < SRSLTE_SUCCESS) { + ERROR("Error DMRS\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +void srslte_ue_dl_nr_free(srslte_ue_dl_nr_t* q) +{ + if (q == NULL) { + return; + } + + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + srslte_ofdm_rx_free(&q->fft[i]); + + if (q->sf_symbols[i] != NULL) { + free(q->sf_symbols[i]); + } + } + + srslte_chest_dl_res_free(&q->chest); + srslte_pdsch_nr_free(&q->pdsch); + srslte_dmrs_pdsch_free(&q->dmrs); + + memset(q, 0, sizeof(srslte_ue_dl_nr_t)); +} + +int srslte_ue_dl_nr_set_carrier(srslte_ue_dl_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_t* sch) +{ + if (srslte_pdsch_nr_set_carrier(&q->pdsch, carrier, sch) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (srslte_dmrs_pdsch_set_carrier(&q->dmrs, carrier) < SRSLTE_SUCCESS) { + ERROR("Error DMRS\n"); + return SRSLTE_ERROR; + } + + if (ue_dl_alloc_prb(q, carrier->nof_prb)) { + ERROR("Error allocating\n"); + return SRSLTE_ERROR; + } + + if (carrier->nof_prb != q->carrier.nof_prb) { + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + srslte_ofdm_rx_set_prb(&q->fft[i], SRSLTE_CP_NORM, carrier->nof_prb); + } + } + + q->carrier = *carrier; + + return SRSLTE_SUCCESS; +} + +void srslte_ue_dl_nr_estimate_fft(srslte_ue_dl_nr_t* q) +{ + if (q == NULL) { + return; + } + + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + srslte_ofdm_rx_sf(&q->fft[i]); + } +} + +int srslte_ue_dl_nr_pdsch_get(srslte_ue_dl_nr_t* q, + const srslte_dl_slot_cfg_t* slot, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + srslte_pdsch_res_nr_t* res) +{ + + if (srslte_dmrs_pdsch_estimate(&q->dmrs, slot, cfg, grant, q->sf_symbols[0], &q->chest) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + printf("ce[0][0]="); + srslte_vec_fprint_c(stdout, q->chest.ce[0][0], q->chest.nof_re); + } + + for (uint32_t i = 0; i < grant->tb->nof_re; i++) { + q->chest.ce[0][0][i] = (1536); + } + + if (srslte_pdsch_nr_decode(&q->pdsch, cfg, grant, &q->chest, q->sf_symbols, res) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/lib/test/phy/CMakeLists.txt b/lib/test/phy/CMakeLists.txt index c65d18ede..2c0d725f5 100644 --- a/lib/test/phy/CMakeLists.txt +++ b/lib/test/phy/CMakeLists.txt @@ -23,7 +23,6 @@ ####################################################################### add_executable(phy_dl_test phy_dl_test.c) target_link_libraries(phy_dl_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) -add_test(phy_dl_test phy_dl_test) # All valid number of PRBs for PUSCH set(ue_dl_min_mcs 0) @@ -63,3 +62,6 @@ target_link_libraries(pucch_ca_test srslte_phy srslte_common srslte_phy ${SEC_LI add_test(pucch_ca_test pucch_ca_test) set_tests_properties(pucch_ca_test PROPERTIES LABELS "long;phy") +add_executable(phy_dl_nr_test phy_dl_nr_test.c) +target_link_libraries(phy_dl_nr_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +add_test(phy_dl_nr_test phy_dl_nr_test) \ No newline at end of file diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c new file mode 100644 index 000000000..aa307338e --- /dev/null +++ b/lib/test/phy/phy_dl_nr_test.c @@ -0,0 +1,278 @@ +/* + * 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/enb/enb_dl_nr.h" +#include "srslte/phy/phch/ra_nr.h" +#include "srslte/phy/ue/ue_dl_nr.h" +#include "srslte/phy/ue/ue_dl_nr_data.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/random.h" +#include "srslte/phy/utils/vector.h" +#include + +static srslte_carrier_nr_t carrier = { + 0, // cell_id + 0, // numerology + 100, // nof_prb + 0 // start +}; + +static uint32_t n_prb = 0; // Set to 0 for steering +static uint32_t mcs = 30; // 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 grant PRB, set to 0 for steering [Default %d]\n", n_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"); +} + +int parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "pmTLv")) != -1) { + switch (opt) { + case 'p': + n_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'm': + mcs = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'T': + pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_from_str(argv[optind]); + break; + case 'L': + pdsch_cfg.sch_cfg.max_mimo_layers = (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_enb_dl_nr_t enb_dl = {}; + srslte_ue_dl_nr_t ue_dl = {}; + srslte_pdsch_res_nr_t pdsch_res[SRSLTE_MAX_TB] = {}; + srslte_random_t rand_gen = srslte_random_init(1234); + srslte_dl_slot_cfg_t slot = {}; + + uint8_t* data_tx[SRSLTE_MAX_TB] = {}; + uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {}; + cf_t* buffer = NULL; + + buffer = srslte_vec_cf_malloc(SRSLTE_SF_LEN_PRB(carrier.nof_prb)); + if (buffer == NULL) { + ERROR("Error malloc\n"); + goto clean_exit; + } + + srslte_ue_dl_nr_args_t ue_dl_args = {}; + ue_dl_args.nof_rx_antennas = 1; + ue_dl_args.pdsch.sch.disable_simd = true; + ue_dl_args.pdsch.measure_evm = true; + + srslte_enb_dl_nr_args_t enb_dl_args = {}; + enb_dl_args.nof_tx_antennas = 1; + enb_dl_args.pdsch.sch.disable_simd = true; + + // Set default PDSCH configuration + pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam; + pdsch_cfg.sch_cfg.max_mimo_layers = 1; + if (parse_args(argc, argv) < SRSLTE_SUCCESS) { + goto clean_exit; + } + + srslte_pdsch_args_t pdsch_args = {}; + pdsch_args.sch.disable_simd = true; + pdsch_args.measure_evm = true; + + if (srslte_ue_dl_nr_init(&ue_dl, &buffer, &ue_dl_args)) { + ERROR("Error UE DL\n"); + goto clean_exit; + } + + if (srslte_enb_dl_nr_init(&enb_dl, &buffer, &enb_dl_args)) { + ERROR("Error UE DL\n"); + goto clean_exit; + } + + if (srslte_ue_dl_nr_set_carrier(&ue_dl, &carrier, &pdsch_cfg.sch_cfg)) { + ERROR("Error setting SCH NR carrier\n"); + goto clean_exit; + } + + if (srslte_enb_dl_nr_set_carrier(&enb_dl, &carrier, &pdsch_cfg.sch_cfg)) { + ERROR("Error setting SCH NR carrier\n"); + goto clean_exit; + } + + for (uint32_t i = 0; i < 1; i++) { + data_tx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR); + data_rx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR); + if (data_tx[i] == NULL || data_rx[i] == NULL) { + ERROR("Error malloc\n"); + goto clean_exit; + } + + pdsch_res[i].payload = data_rx[i]; + } + + srslte_softbuffer_tx_t softbuffer_tx = {}; + srslte_softbuffer_rx_t softbuffer_rx = {}; + + if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < + SRSLTE_SUCCESS) { + ERROR("Error init soft-buffer\n"); + goto clean_exit; + } + + if (srslte_softbuffer_rx_init_guru(&softbuffer_rx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < + 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.sch_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.sch_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); + } + + if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { + ERROR("Error filing tb\n"); + goto clean_exit; + } + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + // Skip TB if no allocated + if (data_tx[tb] == NULL) { + continue; + } + + for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) { + data_tx[tb][i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); + } + pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx; + } + + if (srslte_enb_dl_nr_pdsch_put(&enb_dl, &slot, &pdsch_cfg, &pdsch_grant, data_tx) < SRSLTE_SUCCESS) { + ERROR("Error encoding\n"); + goto clean_exit; + } + + srslte_enb_dl_nr_gen_signal(&enb_dl); + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; + srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx); + } + + srslte_ue_dl_nr_estimate_fft(&ue_dl); + + if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &slot, &pdsch_cfg, &pdsch_grant, pdsch_res) < SRSLTE_SUCCESS) { + ERROR("Error decoding\n"); + goto clean_exit; + } + + if (pdsch_res->evm > 0.001f) { + ERROR("Error PDSCH EVM is too high %f\n", pdsch_res->evm); + goto clean_exit; + } + + if (!pdsch_res[0].crc) { + ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); + goto clean_exit; + } + + if (memcmp(data_tx[0], data_rx[0], pdsch_grant.tb[0].tbs / 8) != 0) { + ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); + printf("Tx data: "); + srslte_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8); + printf("Rx data: "); + srslte_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8); + goto clean_exit; + } + + printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm); + } + } + + ret = SRSLTE_SUCCESS; + +clean_exit: + srslte_random_free(rand_gen); + srslte_enb_dl_nr_free(&enb_dl); + srslte_ue_dl_nr_free(&ue_dl); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data_tx[i]) { + free(data_tx[i]); + } + if (data_rx[i]) { + free(data_rx[i]); + } + } + if (buffer) { + free(buffer); + } + srslte_softbuffer_tx_free(&softbuffer_tx); + srslte_softbuffer_rx_free(&softbuffer_rx); + + return ret; +}