diff --git a/openair1/PHY/CMakeLists.txt b/openair1/PHY/CMakeLists.txt index 83e7dc0530..34629fc1c7 100644 --- a/openair1/PHY/CMakeLists.txt +++ b/openair1/PHY/CMakeLists.txt @@ -3,3 +3,6 @@ add_subdirectory(TOOLS) add_subdirectory(NR_TRANSPORT) add_subdirectory(CODING) add_subdirectory(MODULATION) +if (ENABLE_TESTS) + add_subdirectory(INIT/tests) +endif() \ No newline at end of file diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index cc31dc173a..3e70d8e1a4 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -259,6 +259,55 @@ uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp) return samp_count; } +uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols) +{ + int end_symbol = start_symbol + num_symbols - 1; + AssertFatal(start_symbol <= end_symbol && start_symbol >= 0 && end_symbol < fp->symbols_per_slot, + "Symbol range is invalid start_symbol %d, num_symbols %d symbols_per_slot %d\n", + start_symbol, + num_symbols, + fp->symbols_per_slot); + if (num_symbols == fp->symbols_per_slot) { + return get_samples_per_slot(slot, fp); + } + uint32_t num_samples = 0; + int num_symbols_added = 0; + + // Handle symbols with different nb_prefix_samples0 + if (fp->numerology_index == 0) { + // Add symbol 0 + if (start_symbol == 0) { + num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size; + num_symbols_added++; + } + // Add symbol 7 + if (start_symbol <= 7 && end_symbol >= 7) { + num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size; + num_symbols_added++; + } + } else { + // Add first symbol + if (start_symbol == 0) { + num_samples += (slot % (fp->slots_per_subframe / 2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; + num_samples += fp->ofdm_symbol_size; + num_symbols_added++; + } + } + + int num_symbols_left = max(0, num_symbols - num_symbols_added); + num_samples += num_symbols_left * (fp->nb_prefix_samples + fp->ofdm_symbol_size); + return num_samples; +} + +uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol) +{ + if (symbol == 0) { + return 0; + } + + return get_samples_symbol_duration(fp, slot, 0, symbol); +} + uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp) { uint32_t slot_idx = 0; diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h index f556498f0f..bfe935d93f 100644 --- a/openair1/PHY/INIT/nr_phy_init.h +++ b/openair1/PHY/INIT/nr_phy_init.h @@ -55,10 +55,11 @@ void free_nr_ue_ul_harq(NR_UL_UE_HARQ_t harq_list[NR_MAX_ULSCH_HARQ_PROCESSES], void phy_init_nr_top(PHY_VARS_NR_UE *ue); void phy_term_nr_top(void); +#ifndef __cplusplus void init_delay_table(uint16_t ofdm_symbol_size, int max_delay_comp, int max_ofdm_symbol_size, c16_t delay_table[][max_ofdm_symbol_size]); - +#endif void sl_ue_phy_init(PHY_VARS_NR_UE *UE); #endif diff --git a/openair1/PHY/INIT/tests/CMakeLists.txt b/openair1/PHY/INIT/tests/CMakeLists.txt new file mode 100644 index 0000000000..9f41e0fec0 --- /dev/null +++ b/openair1/PHY/INIT/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(test_nr_frame_params test_nr_frame_params.cpp) +target_link_libraries(test_nr_frame_params PRIVATE LOG minimal_lib PHY_NR -lm GTest::gtest) diff --git a/openair1/PHY/INIT/tests/test_nr_frame_params.cpp b/openair1/PHY/INIT/tests/test_nr_frame_params.cpp new file mode 100644 index 0000000000..ee87120e5a --- /dev/null +++ b/openair1/PHY/INIT/tests/test_nr_frame_params.cpp @@ -0,0 +1,131 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "gtest/gtest.h" +extern "C" { +#include "openair1/PHY/defs_nr_common.h" +#include "openair1/PHY/INIT/nr_phy_init.h" + +static softmodem_params_t softmodem_params; +softmodem_params_t *get_softmodem_params(void) +{ + return &softmodem_params; +} +} + +void test_coherence_symbol_api(NR_DL_FRAME_PARMS *fp) +{ + EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, 0), fp->get_samples_slot_timestamp(0, fp, 0)); + + for (int slot = 0; slot < 4; slot++) { + EXPECT_EQ(get_samples_symbol_duration(fp, slot, 0, fp->symbols_per_slot) + fp->get_samples_slot_timestamp(slot, fp, 0), + fp->get_samples_slot_timestamp(slot + 1, fp, 0)); + } + + for (int symbol = 0; symbol < fp->symbols_per_slot - 1; symbol++) { + EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, symbol + 1) - get_samples_symbol_timestamp(fp, 0, symbol), + get_samples_symbol_duration(fp, 0, symbol, 1)); + } +} + +TEST(nr_frame_params, test_mu_3) +{ + NR_DL_FRAME_PARMS fp; + int mu = NR_MU_3; + memset(&fp, 0, sizeof(fp)); + nfapi_nr_config_request_scf_t cfg; + cfg.carrier_config.num_rx_ant.value = 4; + cfg.carrier_config.num_tx_ant.value = 4; + cfg.carrier_config.dl_grid_size[mu].value = 66; + cfg.carrier_config.ul_grid_size[mu].value = 66; + cfg.cell_config.frame_duplex_type.value = TDD; + cfg.ssb_config.scs_common.value = mu; + fp.dl_CarrierFreq = 27524520000; + fp.nr_band = 261; + nr_init_frame_parms(&cfg, &fp); + nr_dump_frame_parms(&fp); + test_coherence_symbol_api(&fp); +} + +TEST(nr_frame_params, test_mu_2) +{ + NR_DL_FRAME_PARMS fp; + int mu = NR_MU_2; + memset(&fp, 0, sizeof(fp)); + nfapi_nr_config_request_scf_t cfg; + cfg.carrier_config.num_rx_ant.value = 4; + cfg.carrier_config.num_tx_ant.value = 4; + cfg.carrier_config.dl_grid_size[mu].value = 51; + cfg.carrier_config.ul_grid_size[mu].value = 51; + cfg.cell_config.frame_duplex_type.value = TDD; + cfg.ssb_config.scs_common.value = mu; + fp.dl_CarrierFreq = 27524520000; + fp.nr_band = 261; + nr_init_frame_parms(&cfg, &fp); + nr_dump_frame_parms(&fp); + test_coherence_symbol_api(&fp); +} + +TEST(nr_frame_params, test_mu_1) +{ + NR_DL_FRAME_PARMS fp; + int mu = NR_MU_1; + memset(&fp, 0, sizeof(fp)); + nfapi_nr_config_request_scf_t cfg; + cfg.carrier_config.num_rx_ant.value = 4; + cfg.carrier_config.num_tx_ant.value = 4; + cfg.carrier_config.dl_grid_size[mu].value = 106; + cfg.carrier_config.ul_grid_size[mu].value = 106; + cfg.cell_config.frame_duplex_type.value = TDD; + cfg.ssb_config.scs_common.value = mu; + fp.dl_CarrierFreq = 3600000000; + fp.nr_band = 78; + nr_init_frame_parms(&cfg, &fp); + nr_dump_frame_parms(&fp); + test_coherence_symbol_api(&fp); +} + +TEST(nr_frame_params, test_mu_0) +{ + int mu = NR_MU_0; + NR_DL_FRAME_PARMS fp; + memset(&fp, 0, sizeof(fp)); + nfapi_nr_config_request_scf_t cfg; + cfg.carrier_config.num_rx_ant.value = 4; + cfg.carrier_config.num_tx_ant.value = 4; + cfg.carrier_config.dl_grid_size[mu].value = 216; + cfg.carrier_config.ul_grid_size[mu].value = 216; + cfg.cell_config.frame_duplex_type.value = TDD; + cfg.ssb_config.scs_common.value = mu; + fp.dl_CarrierFreq = 2600000000; + fp.nr_band = 38; + nr_init_frame_parms(&cfg, &fp); + nr_dump_frame_parms(&fp); + test_coherence_symbol_api(&fp); +} + +int main(int argc, char **argv) +{ + uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY); + logInit(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 23972fc9f2..a55694ab5b 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -336,4 +336,9 @@ typedef struct { #define KHz (1000UL) #define MHz (1000*KHz) +// Get symbol duration within slot in samples +uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols); +// Get timestamp of symbol within slot in samples +uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol); + #endif